这文章其实不能算原创了只是把别人的代码搬过来注释然后测试一下。
原文链接->http://bbs.pediy.com/showthread.php?t=159536 作者通过修改Context.Eip来达到Hook EIP的目的,不过这种方式我表示在我的win2003上没有成功。同时,作者提供了在github上的源码,源码中作者修改的是Context.Eax。起初很不解,eax跟返回值相关,没见过用eax作为指令地址的。后来找了找进程创建的过程,发现若干资料,其中一篇http://blog.csdn.net/iiprogram/article/details/723356 提到:
“The CONTEXT record was created by CreateProcess, in the case of an Windows create process, and contains the start address according to the loaded exe, and also a thunking location according to the kernel32.dll visable when CreateProcess was run. In fact, the NtContinue thunks on through BaseProcessStartThunk, see nt/private/windows/base/client/context.c. The true starting address is in eax of the CONTEXT, BaseProcessStartThunk is found in eip.”
如果按这篇文章的角度来看SetThreadContext这种注入方式这能用在进程创建的时候,而不像CreateRemoteThread那样灵活。当然,我也尝试了注入到正在运行中的进程,没有效果~
另外关于调试目标进程,很可惜,也没有成功,windbg attach目标进程后windbg的输出是,看着是多线程死锁。希望有高人指教
最后,贴上别人的代码。。。
// DllInjection.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <Windows.h> #include <Shlwapi.h> #pragma comment(lib, "Shlwapi.lib") typedef struct _SHELL_CODE { char szPath[MAX_PATH]; char szInstruction[0x20]; } SHELL_CODE, *PSHELL_CODE; int main(int argc, char* argv[]) { STARTUPINFO SI = {0}; PROCESS_INFORMATION PI = {0}; CONTEXT Context = {0}; LPVOID Buffer = NULL; TCHAR ApplicationName[MAX_PATH] = {0}; TCHAR CurrentDirectory[MAX_PATH] = {0}; /* CopyMemory(ApplicationName, argv[1], sizeof(WCHAR) * (lstrlen(argv[1]) + 1)); CopyMemory(CurrentDirectory, argv[1], sizeof(WCHAR) * (lstrlen(argv[1]) + 1)); if (!PathRemoveFileSpec(CurrentDirectory)) { printf(TEXT("PathRemoveFileSpec failed: %d\n"), GetLastError()); return -1; } */ SI.cb = sizeof(SI); if (!CreateProcess(NULL, "notepad.exe", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) { printf(TEXT("CreateProcess failed: %d\n"), GetLastError()); return -1; } Context.ContextFlags = CONTEXT_INTEGER; if (!GetThreadContext(PI.hThread, &Context)) { printf(TEXT("GetThreadContext failed: %d\n"), GetLastError()); return -1; } CHAR szDllName[] = "Injection.dll"; /* szShellCode转化成汇编代码如下所示 pushad push 0x78563412 mov eax, 0x78563412 call eax popad jmp 0x78563412 */ CHAR szShellCode[] = "\x60\x68\x12\x34\x56\x78\xb8\x12\x34\x56\x78\xff\xd0\x61\xe9\x12\x34\x56\x78"; Buffer = VirtualAllocEx(PI.hProcess, NULL, sizeof(SHELL_CODE), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (Buffer == NULL) { printf(TEXT("Failed to allocate buffer in the target process\n")); return -1; } //Buffer指向SHELL_CODE结构,Buffer的起始地址正好是szPath结构的偏移 //这行将push 0x78563412中0x78563412替换为szPath的地址,作为LoadLibraryA的参数 *(DWORD*)(szShellCode + 2) = (DWORD)Buffer; //这行将mov eax, 0x78563412中0x78563412替换为LoadLibraryA地址 *(DWORD*)(szShellCode + 7) = (DWORD)LoadLibraryA; //shellcode中e9对应jmp相对跳转方式;CreateProcess(...CREATE_SUSPENDED...);创建进程时 //线程将要执行的指令所在的内存存放在Context.Eax中 //shellcode执行完毕,eip指向下一条指令的内存, //该内存在(PUCHAR)Buffer + FIELD_OFFSET(SHELL_CODE, szInstruction) + sizeof(szShellCode)之后 //此处计算Context.Eax与shellcode执行完毕后地址差,作为jmp的跳转地址,替换jmp 0x78563412中的0x78563412 *(DWORD*)(szShellCode + 15) = Context.Eax - (DWORD)((PUCHAR)Buffer + FIELD_OFFSET(SHELL_CODE, szInstruction) + sizeof(szShellCode) - 1); SHELL_CODE ShellCode; CopyMemory(((PSHELL_CODE)&ShellCode)->szPath, szDllName, sizeof(szDllName)); CopyMemory(((PSHELL_CODE)&ShellCode)->szInstruction, szShellCode, sizeof(szShellCode)); DWORD NumberOfBytesWritten = 0; if (!WriteProcessMemory(PI.hProcess, Buffer, &ShellCode, sizeof(SHELL_CODE), &NumberOfBytesWritten)) { printf(TEXT("WriteProcessMemory failed: %d\n"), GetLastError()); return -1; } Context.Eax = (DWORD)(((PSHELL_CODE)Buffer)->szInstruction); if (!SetThreadContext(PI.hThread, &Context)) { printf(TEXT("SetThreadContext failed: %d\n"), GetLastError()); return -1; } ResumeThread(PI.hThread); return 0; }