ctypes,getErrorCode6,LoadLibrary和Modulehandle是否返回None?

2024-07-05 11:49:02 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在学习更多关于ctypes及其函数的知识,我正在尝试创建一个脚本,通过它的PID(process ID)WriteProcessMemory放到记事本中。然而,当我试图执行脚本时,记事本立即崩溃。我遵循this的教程,我认为这与“Gray Hat for Hacking Python”一书是一样的。正确地说,执行的shell代码应该创建一个消息框。你知道吗

这是我的密码。你知道吗

import os
import colorama
from colorama import Fore, Back, Style
import win32com.client
from ctypes import *

from ctypes import wintypes
import ctypes
from ctypes.wintypes import BOOL
from ctypes.wintypes import DWORD
from ctypes.wintypes import HANDLE
from ctypes.wintypes import LPVOID
from ctypes.wintypes import LPCVOID
from ctypes.wintypes import LPCWSTR

colorama.init()
kernel32 = ctypes.WinDLL('Kernel32', use_last_error=True)

LPCSTR = LPCTSTR = ctypes.c_char_p
LPDWORD = PDWORD = ctypes.POINTER(DWORD)
class _SECURITY_ATTRIBUTES(ctypes.Structure):
    _fields_ = [('nLength', DWORD),
                ('lpSecurityDescriptor', LPVOID),
                ('bInheritHandle', BOOL),]
SECURITY_ATTRIBUTES = _SECURITY_ATTRIBUTES
LPSECURITY_ATTRIBUTES = ctypes.POINTER(_SECURITY_ATTRIBUTES)
LPTHREAD_START_ROUTINE = LPVOID

OpenProcess = kernel32.OpenProcess
OpenProcess.restype = HANDLE
OpenProcess.argtypes = (DWORD, BOOL, DWORD)

VirtualAllocEx = kernel32.VirtualAllocEx
VirtualAllocEx.restype = LPVOID
VirtualAllocEx.argtypes = (HANDLE, LPVOID, ctypes.c_size_t, DWORD, DWORD)

ReadProcessMemory = kernel32.ReadProcessMemory
ReadProcessMemory.restype = BOOL
ReadProcessMemory.argtypes = (HANDLE, LPCVOID, LPVOID, DWORD, DWORD)

WriteProcessMemory = kernel32.WriteProcessMemory
WriteProcessMemory.restype = BOOL
WriteProcessMemory.argtypes = (HANDLE, LPVOID, LPCVOID, DWORD, ctypes.c_int)

CreateRemoteThread = kernel32.CreateRemoteThread
CreateRemoteThread.restype = HANDLE
CreateRemoteThread.argtypes = (HANDLE, LPSECURITY_ATTRIBUTES, ctypes.c_size_t , LPTHREAD_START_ROUTINE, LPVOID, DWORD, ctypes.c_ulong)

GetLastError = kernel32.GetLastError
GetLastError.restype = DWORD
GetLastError.argtypes = ()

GetModuleHandle = kernel32.GetModuleHandleA
GetModuleHandle.restype = HANDLE
GetModuleHandle.argtypes =  (LPCWSTR,)

GetProcAddress = kernel32.GetProcAddress
GetProcAddress.restype = LPVOID
GetProcAddress.argtypes = (HANDLE, LPCWSTR)

# https://www.aldeid.com/wiki/Process-Security-and-Access-Rights
PROCESS_VM_READ = 0x0010 # Required to read memory in a process using ReadProcessMemory. 
PROCESS_VM_WRITE = 0x0020
PROCESS_VM_OPERATION = 0x0008 # Required to write to memory in a process using WriteProcessMemory. 
PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_CREATE_THREAD = 0x0002
PROCESS_ALL_ACCESS = (PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD) #0x1F0FFF

print(Fore.RED + 'Retrieving PIDs...')
WMI= win32com.client.GetObject('winmgmts:')
processes = WMI.ExecQuery('SELECT * from win32_process')
print(Fore.GREEN)
process_list = [i.Properties_('ProcessId').Value for i in processes] # list of available processes
for process in processes:
    print(process.Properties_('ProcessId').Value , " - " , process.Properties_('Name').Value)

PID = int(input('Enter the PID of the process '))


# https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
process_handle = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, PID) # creating the handle
if not process_handle:
    print ("Couldn't acquire a handle to PID: %s" % PID)


shellcode = "C:\\Users\\User\\Desktop\\py\\injector\\hello-world-x64.dll"


# https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex

memory_alloc = kernel32.VirtualAllocEx(process_handle,0, len(shellcode), (0x1000 | 0x2000), 0x40) # allocating memory to the process
write = kernel32.WriteProcessMemory(process_handle, memory_alloc, shellcode, len(shellcode), 0) 

ModuleHandle = kernel32.GetModuleHandleA('kernel32.dll')
LoadLibraryA = kernel32.GetProcAddress(ModuleHandle,"LoadLibraryA")

if not kernel32.CreateRemoteThread(process_handle, None, 0, LoadLibraryA, memory_alloc, 0, 0):
    print("Failed injection..")

print("ModuleHandle : ", ModuleHandle)
print("LoadLibrary : ", LoadLibraryA)
print("process handle : ", process_handle)
print("VirtualAllocEx : ",memory_alloc)
print("WriteProcessMemory : ",write)

print(ctypes.GetLastError())

我试过打印返回值,很明显给我错误的是ModuleHandleLoadLibrary,返回的是None值。但据微软称:

If the function succeeds, the return value is nonzero. If the function fails, the return value is 0 (zero). To get extended error information, call GetLastError. The function fails if the requested write operation crosses into an area of the process that is inaccessible.

我还尝试了GetLastError()方法,该方法返回6,在google上,它表示“无效处理程序”。你知道吗

如果有帮助的话,我的操作系统、记事本、VScode(我的ide)、python(3.6.8)都是64位的。 我为混乱的代码道歉,请随时纠正我,因为我在这方面是一个完全的初学者。你知道吗

编辑

这是我打印输出的图像。我也试过LoadLibraryWGetModuleHandleW,但也没用,我的记事本坏了。我使用的dll是一个普通的dll文件,它只会生成一个消息框,说“helloworld” enter image description here


Tags: thefromimportctypesprocesshandleprintdword
1条回答
网友
1楼 · 发布于 2024-07-05 11:49:02

好吧,我在写这个脚本时犯了很多错误,@eryksun在评论部分给出了很多精彩的答案。我写这个答案是为了巩固我所学到的东西。你知道吗

1)我应该用kernel32 = ctypes.WinDLL('Kernel32', use_last_error=True)而不是kernel32 = ctypes.windll.kernel32。这避免了与使用windll的其他模块的冲突。它还可以保护线程的LastErrorValue。在这种情况下,请使用ctypes.get_last_error()ctypes.set_last_error(err),而不是直接调用WinAPI GetLastErrorSetLastError。你知道吗

2)WriteProcessMemory.argtypes = (HANDLE, LPVOID, LPCVOID, DWORD, ctypes.c_int)设置错误。argtype根据文档,应该是:

BOOL WriteProcessMemory(
  HANDLE  hProcess,
  LPVOID  lpBaseAddress,
  LPCVOID lpBuffer,
  SIZE_T  nSize,
  SIZE_T  *lpNumberOfBytesWritten
);

其中最后两个参数应该是[HANDLE, LPVOID, LPCVOID, SIZE_T, PSIZE_T]。你知道吗

3)PROCESS_ALL_ACCESS只应获得CreateRemoteThreadWriteProcessMemory所需的必要权利,这些权利是PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION。你知道吗

4)与其将我传递的字节大小分配为len(shellcode),不如将其分配为(len(shellcode) + 1) * WCHAR_SIZE。你知道吗

In general you should factor in the null terminator when copying a string, e.g. use len(dll_path) + 1. In this case you're committing a new page of memory (4 KiB on x86 and x64 systems), which is initially all zeros.

If you're using Python 3, then the DLL path is passed as a wide-character, null-terminated string, which explains the need for plus 1 (the trailing null character) and the need to multiply by WCHAR_SIZE (two bytes per character).

WriteProcessMemory is just writing the path as a string in the address space of the target process. This is passed as a parameter to LoadLibraryW (the native "W" version for a wide-character Unicode string), which is called in the target process on a new remote thread. Notice that LoadLibraryW is at the same address in the target process as our current process, because kernel32.dll is always mapped at its preferred base address, and it's always loaded in a Windows process. That's not necessarily the case for most other DLLs.

5)GetModuleHandleALoadLibraryA应替换为各自的W函数。此外,GetModuleHandleWGetProcAddress步骤是不必要的。ctypes已经帮你做了。只需使用kernel32.LoadLibraryW。这取决于kernel32.dll在每个进程中总是映射到相同的基址,我认为对于现有版本的Windows也是如此。你知道吗

DOS and Windows 9x used codepages to encode strings (i.e. a mapping between ordinal values and characters) for a given locale, such as 437 for the U.S., 850 for Western Europe, and 1252 in Windows for both regions. OTOH, Windows NT (1993) was based on Unicode (i.e. one character set that supports all written languages), and it needed to provide compatibility with Windows 9x applications that didn't support Unicode.

NT defined two codepages per locale, an OEM (DOS) codepage and an ANSI (Windows) codepage. Functions had a [W]ide-character version (e.g. GetModuleHandleW) and a wrapped [A]NSI version (e.g. GetModuleHandleA). The wrapper translated between ANSI and Unicode and called the wide-character function. At the API level, the headers defined one or the other, depending on whether UNICODE was defined. Additionally this system defined TCHAR string types such as LPTSTR that are mapped to either the narrow type such as LPSTR or the wide-character type such as LPWSTR

Since Windows XP, all supported versions of Windows have been based on Windows NT, and many new functions added to the API are only available in wide-character versions (e.g. GetLocaleInfoEx; note the lack of a "W" suffix in this case because there's only one version). The old ANSI API and TCHAR types are a legacy now. I recommend only using the native wide-character API with Unicode strings.

感谢@eryksun的帮助!你知道吗

相关问题 更多 >