class DynamicDetect(object):

    def __init__(self, target_pcmd):
        self.KnownDlls = []
        self.LoadedDlls = []
        self.QuickAnalysisRes = []
        self.QuickAnalysisRes2 = []
        self.ThirdPartyDlls = []
        self.SigCheckRes = []
        self.target_pcmd = target_pcmd.split()
        self.process = None
        self.tmp_monitor = None
        self.Psapi = WinDLL('Psapi.dll')
        self.Kernel32 = WinDLL('kernel32.dll')

    def checkPath(self):
        return os.access(self.exePathName, os.X_OK)

    def GetKnownDlls(self):
        handler = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager')
        key = winreg.OpenKey(handler, 'KnownDlls')
        index = 0
        while True:
            try:
                self.KnownDlls.append(winreg.EnumValue(key, index)[1])
                index += 1
            except:
                break

    def standardize(self, module_list):
        new_module_list = []
        for module in module_list:
            parsed = module.split('\\')
            if (parsed[0] == 'C:'
                    and parsed[1] == 'Windows'
                    and (parsed[2] == 'System32'
                         or parsed[2] == 'SYSTEM32'
                         or parsed[2] == 'SysWOW64')):
                new_module_list.append(parsed[-1].lower())
            else:
                new_module_list.append(module.lower())
        return new_module_list

    def StartProcess(self):
        print(self.target_pcmd)
        self.process = subprocess.Popen(self.target_pcmd, shell=False)
        return self.process.pid

    def KillProcess(self):
        self.process.terminate()

    def GetLoadedDlls(self):

        PROCESS_QUERY_INFORMATION = 0x0400
        PROCESS_VM_READ = 0x0010

        LIST_MODULES_ALL = 0x03

        def EnumProcessModulesEx(hProcess):
            buf_count = 256
            while True:
                buf = (HMODULE * buf_count)()
                buf_size = sizeof(buf)
                needed = DWORD()
                if not self.Psapi.EnumProcessModulesEx(hProcess, byref(buf), buf_size,
                                                       byref(needed), LIST_MODULES_ALL):
                    raise OSError('EnumProcessModulesEx failed')
                if buf_size < needed.value:
                    buf_count = needed.value // (buf_size // buf_count)
                    continue
                count = needed.value // (buf_size // buf_count)
                return map(HMODULE, buf[:count])

        def GetModuleFileNameEx(hProcess, hModule):
            buf = create_unicode_buffer(MAX_PATH)
            nSize = DWORD()
            if not self.Psapi.GetModuleFileNameExW(hProcess, hModule,
                                                   byref(buf), byref(nSize)):
                raise OSError('GetModuleFileNameEx failed')
            return buf.value

        def get_process_modules(pid):
            hProcess = self.Kernel32.OpenProcess(
                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                False, pid)
            if not hProcess:
                raise OSError('Could not open PID %s' % pid)
            try:
                return [
                    GetModuleFileNameEx(hProcess, hModule)
                    for hModule in EnumProcessModulesEx(hProcess)]
            finally:
                self.Kernel32.CloseHandle(hProcess)

        try:
            dll_list = get_process_modules(self.process.pid)[1:]
            self.LoadedDlls = dll_list
        except OSError as ose:
            print(str(ose))
            self.LoadedDlls = []

    def QuickAnalysis(self):
        if self.checkPath():
            prefix = '\\'.join(self.target_pcmd[0].lower().split(' ')[0].split('\\')[:-1])
            Sys_prefix = ['c:\\windows\\system32\\', 'c:\\windows\\syswow64\\']
            self.StartProcess()
            print("Waiting Your Click")  # How to judge the status of a process?
            input()
            self.GetKnownDlls()
            self.KnownDlls = self.standardize(self.KnownDlls)
            self.GetLoadedDlls()
            self.LoadedDlls = self.standardize(self.LoadedDlls)
            for i in self.LoadedDlls:
                i = i.replace(Sys_prefix[0], '').replace(Sys_prefix[1], '')
                if (i not in self.KnownDlls) and (i not in whiteList[0]):
                    if not i.startswith(prefix):
                        self.QuickAnalysisRes.append(i)
                        if i not in whiteList[1]:
                            self.QuickAnalysisRes2.append(i)
                    elif not (i.startswith(Sys_prefix[0]) or i.startswith(Sys_prefix[1])):
                        self.ThirdPartyDlls.append(i)
            self.KillProcess()
            return 1
        return 0
Example #2
0
class MemCtrl:
    PID = None
    procHandle = None
    # dll
    dllAddr = None
    mono_compile_method_addr = None
    mono_class_get_method_from_name_addr = None
    targetDllPath = None

    def __init__(self):
        self.kernel32 = WinDLL('kernel32', use_last_error=True)

    def isOpenProcess(self):
        return self.procHandle != None

    def openProcess(self, procName):
        pids = win32pdhutil.FindPerformanceAttributesByName(
            procName, None, None, win32pdh.PDH_FMT_LONG, None, True)
        print(pids)
        if len(pids) == 0:
            print("fail")
            return False
        elif len(pids) > 0:
            self.PID = pids[0]
            self.procHandle = self.kernel32.OpenProcess(
                privileges['PROCESS_ALL_ACCESS'], False, self.PID)
            self.baseAddr = win32process.EnumProcessModulesEx(
                self.procHandle)[0]
            return True

    def monoFeature(self):
        self.getTargetDllPath()
        self.injectDllInit()

    def createRemoteThreadByVal(self, funcAddr, args):

        dllAddr = c_int(0)
        thread = self.kernel32.CreateRemoteThread(self.procHandle, None, None,
                                                  c_int(funcAddr), c_int(args),
                                                  None, None)
        if not thread:
            raise WinError()
        if self.kernel32.WaitForSingleObject(thread, INFINITE) == WAIT_FAILED:
            raise WinError()
        if not self.kernel32.GetExitCodeThread(thread, byref(dllAddr)):
            raise WinError()

        return dllAddr.value

    def createRemoteThreadByRef(self, funcAddr, args):

        dllAddr = c_int(0)
        argsAddr = self.allocRemoteMem(args, len(args))
        thread = self.kernel32.CreateRemoteThread(self.procHandle, None, None,
                                                  c_int(funcAddr),
                                                  c_int(argsAddr), None, None)
        if not thread:
            raise WinError()
        if self.kernel32.WaitForSingleObject(thread, INFINITE) == WAIT_FAILED:
            raise WinError()
        if not self.kernel32.GetExitCodeThread(thread, byref(dllAddr)):
            raise WinError()
        self.virtualFreeEX(argsAddr)
        return dllAddr.value

    def mono_compile_method(self, method):
        return self.createRemoteThreadByVal(self.mono_compile_method_addr,
                                            method)

    def getJITAddr(self, className, methodName):

        dllPathBytes = self.targetDllPath.encode('utf-8')
        dllPathAddr = self.allocRemoteMem(dllPathBytes, len(dllPathBytes))

        clsNameBytes = className.encode('utf-8')
        clsNameAddr = self.allocRemoteMem(clsNameBytes, len(clsNameBytes))

        funcNameBytes = methodName.encode('utf-8')
        funcNameAddr = self.allocRemoteMem(funcNameBytes, len(funcNameBytes))

        args = struct.pack("3i", dllPathAddr, clsNameAddr, funcNameAddr)
        methodId = self.createRemoteThreadByRef(
            self.mono_class_get_method_from_name_addr, args)

        self.virtualFreeEX(dllPathAddr)
        self.virtualFreeEX(clsNameAddr)
        self.virtualFreeEX(funcNameAddr)

        return self.mono_compile_method(methodId)

    def injectDllInit(self):
        path_dll = os.path.abspath("MonoInjector.dll")
        buffer = path_dll.encode("ascii")
        funcAddr = self.get_address_from_module("kernel32.dll", "LoadLibraryA")
        self.dllAddr = self.createRemoteThreadByRef(funcAddr, buffer)
        print("Dll Address%x" % self.dllAddr)
        self.mono_compile_method_addr = self.getFuncAddr(
            "MonoInjector.dll", b"do_mono_compile_method", self.dllAddr)
        self.mono_class_get_method_from_name_addr = self.getFuncAddr(
            "MonoInjector.dll", b"do_mono_class_get_method_from_name",
            self.dllAddr)

    def getTargetDllPath(self):
        procName = win32process.GetModuleFileNameEx(self.procHandle, 0)
        folder = Path(procName).parent.absolute()
        for root, _, files in os.walk(folder):
            for name in files:
                if name == "Assembly-CSharp.dll":
                    self.targetDllPath = os.path.abspath(
                        os.path.join(root, name))

    def getFuncAddr(self, module, function, targetBaseAddr):
        module_addr = self.kernel32.LoadLibraryExW(
            module, None, loadLibraryFlags['DONT_RESOLVE_DLL_REFERENCES'])
        funcAddr = self.kernel32.GetProcAddress(module_addr, function)
        targetProc = funcAddr - module_addr + targetBaseAddr
        return targetProc

    def get_address_from_module(self, module, function):
        module_addr = self.kernel32.GetModuleHandleA(module.encode("ascii"))
        if not module_addr:
            raise WinError()
        funcAddr = self.kernel32.GetProcAddress(module_addr,
                                                function.encode("ascii"))
        if not module_addr:
            raise WinError()
        return funcAddr

    def ReadProcessMemory(self, targetAddr, buf):
        size = len(buf)
        return self.kernel32.ReadProcessMemory(self.procHandle, targetAddr,
                                               buf, size, 0)

    def WriteProcessMemory(self, targetAddr, buf):
        size = len(buf)
        self.kernel32.WriteProcessMemory(self.procHandle, targetAddr, buf,
                                         size, 0)

    def virtualFreeEX(self, addr):
        if self.procHandle != None:
            if (self.kernel32.VirtualFreeEx(
                    self.procHandle, addr, 0,
                    memFree_types['MEM_RELEASE']) == 0):
                raise MemCtrlError('Failed virtualFree ' +
                                   '{}'.format(self.get_last_error()))

    def allocExecMem(self):
        baseaddress = self.kernel32.VirtualAllocEx(
            self.procHandle, 0, 0x400, mem_states['MEM_COMMIT'],
            page_protections['PAGE_EXECUTE_READWRITE'])
        assert baseaddress != 0
        return baseaddress

    def allocRemoteMem(self, buffer, size):
        alloc = self.allocMem(size)
        self.WriteProcessMemory(alloc, buffer)
        return alloc

    def allocMem(self, size):
        alloc = self.kernel32.VirtualAllocEx(
            self.procHandle, None, c_int(size), mem_states['MEM_CREATE'],
            page_protections['PAGE_EXECUTE_READWRITE'])
        if not alloc:
            raise WinError()
        return alloc

    def CloseHandle(self):
        if self.procHandle != None:
            self.kernel32.CloseHandle(self.procHandle)
            print('close')