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
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')