在《Windows核心编程》第22章第6小节中有这么一段描述:22.6 把DLL作为调试器来注入调试程序能够对被调试的进程执行特殊的操作。当被调试进程加载时,在被调试进程的地址空间已经作好准备,但是被调试进程的主线程尚未执行任何代码之前,系统将自动将这个情况通知调试程序。这时,调试程序可以强制将某些代码插入被调试进程的地址空间中(比如使用WriteProcessMemory函数来插入),然后使被调试进程的主线程执行该代码。这种方法要求你对被调试线程的CONTEXT结构进行操作,意味着必须编写特定CPU的代码。必须修改你的源代码,使之能够在不同的CPU平台上正确地运行。另外,必须对你想让被调试进程执行的机器语言指令进行硬编码。而且调试程序与它的被调试程序之间必须存在固定的关系。如果调试程序终止运行,Windows将自动撤消被调试进程。而你则无法阻止它。根据上面的原理,下面的代码哪里写错了,一直都不能把DLL注入到目标进程中:#include <windows.h>
#include <strsafe.h>
#include <stddef.h>#pragma comment(lib,"strsafe")//B8 00000000 mov eax, &szDllPath
//50 push eax
//B9 00000000 mov ecx, &LoadLibrary
//FFD1 call ecx
//CC int3typedef struct _INJECT_CODE
{
BYTE byMOV_EAX;
DWORD dwMOV_EAX_VALUE;
BYTE byPUSH_EAX;
BYTE byMOV_ECX;
DWORD dwMOV_ECX_VALUE;
WORD wCALL_ECX;
BYTE byINT3;
CHAR szDllPath[MAX_PATH];
}INJECT_CODE,*PINJECT_CODE;BOOL InjectDebuggeeCode(HANDLE hProcess,LPVOID lpBaseAddress,PCHAR szDllPath)
{
BOOL fSuccess = FALSE;
INJECT_CODE ic = {sizeof(ic)};
ic.byMOV_EAX = 0xB8;
ic.dwMOV_EAX_VALUE = (DWORD)lpBaseAddress + offsetof(INJECT_CODE,szDllPath);
ic.byPUSH_EAX = 0x50;
ic.byMOV_ECX = 0xB9;
ic.dwMOV_ECX_VALUE = (DWORD)&LoadLibrary;
ic.wCALL_ECX = 0xD1FF;
ic.byINT3 = 0xCC;
StringCbCopy(ic.szDllPath,MAX_PATH,szDllPath);
fSuccess = WriteProcessMemory(hProcess,lpBaseAddress,&ic,sizeof(ic),NULL);
if(!fSuccess)printf("Error:%d,Inject Debuggee Code Failed.",GetLastError());
fSuccess = FlushInstructionCache(hProcess,lpBaseAddress,sizeof(ic));
if(!fSuccess)printf("Error:%d,Flush Debuggee Code Failed.",GetLastError());
return fSuccess;
}int main(int argc,char **argv)
{
DWORD dwProcessId = 0;
char *endptr = "\0";
BOOL fSuccess = FALSE,fFirst = TRUE;
LPVOID lpBaseAddress = NULL;
HANDLE hThread = NULL, hProcess = NULL;
DEBUG_EVENT dbgEvent = {0};
CONTEXT ctxOld = {CONTEXT_FULL},ctxNew = {CONTEXT_FULL};
INJECT_CODE ic = {0};
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi = {0};
if(argc != 3)
{
printf("Usage:InjDebuggee.exe <PID> <Be Inject Dll Path>");
return 0;
}
dwProcessId = strtol(argv[1],&endptr,10);
fSuccess = DebugActiveProcess(dwProcessId);
if(!fSuccess){printf("Debug Process [%d] Failed.",dwProcessId);return 0;}
//CreateProcess(NULL,"IpMsg.exe",NULL,NULL,FALSE,DEBUG_ONLY_THIS_PROCESS,NULL,NULL,&si,&pi);
//本程序退出时,防止被调试进程也一并退出
DebugSetProcessKillOnExit(FALSE);
while(WaitForDebugEvent(&dbgEvent,INFINITE))
{
switch(dbgEvent.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT :
hProcess = dbgEvent.u.CreateProcessInfo.hProcess;
hThread = dbgEvent.u.CreateProcessInfo.hThread;
//分配内存,填充注入指令
lpBaseAddress = VirtualAllocEx(hProcess,
NULL,
sizeof(INJECT_CODE),
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
if(NULL == lpBaseAddress)
{
printf("Can not alloc enough memory");
return 0;
}
fSuccess = InjectDebuggeeCode(hProcess,lpBaseAddress,argv[2]);
if(!fSuccess) return 0;
//获取当前线程上下文
GetThreadContext(hThread,&ctxOld);
ctxNew = ctxOld;
ctxNew.Eip = (DWORD)lpBaseAddress;
printf("New Eip = 0x%08X\n",ctxNew.Eip);
//设置新的线程上下文
SetThreadContext(hThread,&ctxNew);
break;
case EXCEPTION_DEBUG_EVENT :
if(dbgEvent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
{
if(fFirst)
{
fFirst = FALSE;
ContinueDebugEvent(dbgEvent.dwProcessId,dbgEvent.dwThreadId,DBG_CONTINUE);
continue;
}
else
{
hProcess= OpenProcess(PROCESS_ALL_ACCESS,
FALSE,
dbgEvent.dwProcessId);
hThread = OpenThread(THREAD_ALL_ACCESS,
FALSE,
dbgEvent.dwThreadId);
GetThreadContext(hThread,&ctxNew);
printf("Second Exception Eip = 0x%08X\n",ctxNew.Eip);
//释放内存
VirtualFreeEx(hProcess,
lpBaseAddress,
sizeof(INJECT_CODE),
MEM_RELEASE);
//设置原先的线程上下文
SetThreadContext(hThread,&ctxOld);
CloseHandle(hThread);
CloseHandle(hProcess);
return 0;
}
}
break;
}
ContinueDebugEvent(dbgEvent.dwProcessId,dbgEvent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);
}
}
#include <strsafe.h>
#include <stddef.h>#pragma comment(lib,"strsafe")//B8 00000000 mov eax, &szDllPath
//50 push eax
//B9 00000000 mov ecx, &LoadLibrary
//FFD1 call ecx
//CC int3typedef struct _INJECT_CODE
{
BYTE byMOV_EAX;
DWORD dwMOV_EAX_VALUE;
BYTE byPUSH_EAX;
BYTE byMOV_ECX;
DWORD dwMOV_ECX_VALUE;
WORD wCALL_ECX;
BYTE byINT3;
CHAR szDllPath[MAX_PATH];
}INJECT_CODE,*PINJECT_CODE;BOOL InjectDebuggeeCode(HANDLE hProcess,LPVOID lpBaseAddress,PCHAR szDllPath)
{
BOOL fSuccess = FALSE;
INJECT_CODE ic = {sizeof(ic)};
ic.byMOV_EAX = 0xB8;
ic.dwMOV_EAX_VALUE = (DWORD)lpBaseAddress + offsetof(INJECT_CODE,szDllPath);
ic.byPUSH_EAX = 0x50;
ic.byMOV_ECX = 0xB9;
ic.dwMOV_ECX_VALUE = (DWORD)&LoadLibrary;
ic.wCALL_ECX = 0xD1FF;
ic.byINT3 = 0xCC;
StringCbCopy(ic.szDllPath,MAX_PATH,szDllPath);
fSuccess = WriteProcessMemory(hProcess,lpBaseAddress,&ic,sizeof(ic),NULL);
if(!fSuccess)printf("Error:%d,Inject Debuggee Code Failed.",GetLastError());
fSuccess = FlushInstructionCache(hProcess,lpBaseAddress,sizeof(ic));
if(!fSuccess)printf("Error:%d,Flush Debuggee Code Failed.",GetLastError());
return fSuccess;
}int main(int argc,char **argv)
{
DWORD dwProcessId = 0;
char *endptr = "\0";
BOOL fSuccess = FALSE,fFirst = TRUE;
LPVOID lpBaseAddress = NULL;
HANDLE hThread = NULL, hProcess = NULL;
DEBUG_EVENT dbgEvent = {0};
CONTEXT ctxOld = {CONTEXT_FULL},ctxNew = {CONTEXT_FULL};
INJECT_CODE ic = {0};
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi = {0};
if(argc != 3)
{
printf("Usage:InjDebuggee.exe <PID> <Be Inject Dll Path>");
return 0;
}
dwProcessId = strtol(argv[1],&endptr,10);
fSuccess = DebugActiveProcess(dwProcessId);
if(!fSuccess){printf("Debug Process [%d] Failed.",dwProcessId);return 0;}
//CreateProcess(NULL,"IpMsg.exe",NULL,NULL,FALSE,DEBUG_ONLY_THIS_PROCESS,NULL,NULL,&si,&pi);
//本程序退出时,防止被调试进程也一并退出
DebugSetProcessKillOnExit(FALSE);
while(WaitForDebugEvent(&dbgEvent,INFINITE))
{
switch(dbgEvent.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT :
hProcess = dbgEvent.u.CreateProcessInfo.hProcess;
hThread = dbgEvent.u.CreateProcessInfo.hThread;
//分配内存,填充注入指令
lpBaseAddress = VirtualAllocEx(hProcess,
NULL,
sizeof(INJECT_CODE),
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
if(NULL == lpBaseAddress)
{
printf("Can not alloc enough memory");
return 0;
}
fSuccess = InjectDebuggeeCode(hProcess,lpBaseAddress,argv[2]);
if(!fSuccess) return 0;
//获取当前线程上下文
GetThreadContext(hThread,&ctxOld);
ctxNew = ctxOld;
ctxNew.Eip = (DWORD)lpBaseAddress;
printf("New Eip = 0x%08X\n",ctxNew.Eip);
//设置新的线程上下文
SetThreadContext(hThread,&ctxNew);
break;
case EXCEPTION_DEBUG_EVENT :
if(dbgEvent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
{
if(fFirst)
{
fFirst = FALSE;
ContinueDebugEvent(dbgEvent.dwProcessId,dbgEvent.dwThreadId,DBG_CONTINUE);
continue;
}
else
{
hProcess= OpenProcess(PROCESS_ALL_ACCESS,
FALSE,
dbgEvent.dwProcessId);
hThread = OpenThread(THREAD_ALL_ACCESS,
FALSE,
dbgEvent.dwThreadId);
GetThreadContext(hThread,&ctxNew);
printf("Second Exception Eip = 0x%08X\n",ctxNew.Eip);
//释放内存
VirtualFreeEx(hProcess,
lpBaseAddress,
sizeof(INJECT_CODE),
MEM_RELEASE);
//设置原先的线程上下文
SetThreadContext(hThread,&ctxOld);
CloseHandle(hThread);
CloseHandle(hProcess);
return 0;
}
}
break;
}
ContinueDebugEvent(dbgEvent.dwProcessId,dbgEvent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);
}
}
思路检查下,正确就OK。对照其实只要单步的话,就能定位出问题所在了。
Java的老兄,VC的IDE还用的惯吧?
/*
pushadpush szDllmov eax, &LoadLibraryAcall eax // 实现调用LoadLibrary(szDll)的代码mov eax, oldentryjmp eax // 实现在LoadLibrary运行完后, 跳至目标进程的入口继续运行 */// FileMaping的结构体typedef struct { LPBYTE lpEntryPoint; // 目标进程的入口地址 BYTE oldcode[sizeof(INJECT_CODE)]; // 目标进程的代码保存}SPY_MEM_SHARE, * LPSPY_MEM_SHARE;
/*
准备工作:第一步:用CreateProcess(CREATE_SUSPENDED)启动目标进程。
*/
CreateProcessA(0, szRunFile, 0, 0, FALSE, CREATE_SUSPENDED 0, NULL, &stInfo, &m_proInfo) ;// 用CreateProcess启动一个暂停的目标进程// 找到目标进程的入口点,函数如下//第二步:找到目标进程的入口,用ImageHlp中的函数可以实现。pEntryPoint = GetExeEntryPoint(szRunFile);LPBYTE GetExeEntryPoint(char *filename){ PIMAGE_NT_HEADERS pNTHeader; DWORD pEntryPoint; PLOADED_IMAGE pImage; pImage = ImageLoad(filename, NULL); if(pImage == NULL) return NULL; pNTHeader = pImage->FileHeader; pEntryPoint = pNTHeader->OptionalHeader.AddressOfEntryPoint + pNTHeader->OptionalHeader.ImageBase; ImageUnload(pImage); return (LPBYTE)pEntryPoint;}
// 创建FileMappinghMap = CreateFileMapping((HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, sizeof(SPY_MEM_SHARE), “MyDllMapView”); // 保存目标进程的代码//第三步:将目标进程入口的代码保存起来。LPSPY_MEM_SHARE lpMap = pMapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);ReadProcessMemory(m_proInfo.hProcess, pEntryPoint, &lpMap->oldcode, sizeof(INJECT_CODE), &cBytesMoved); lpMap->lpEntryPoint = pEntryPoint; // 第四步:在目标进程的入口写入LoadLibrary(MyDll)实现Dll的注入。// 准备注入DLL的代码 INJECT_CODE newCode;// 写入MyDll―――用全路径 lstrcpy(newCode.szDLL, szMyDll);// 准备硬代码(汇编代码) newCode.int_PUSHAD = 0x60; newCode.int_PUSH = 0x68; newCode.int_MOVEAX = 0xB8; newCode.call_eax = 0xD0FF; newCode.jmp_MOVEAX = 0xB8; newCode.jmp_eax = 0xE0FF; newCode.eax_Value = (DWORD)&LoadLibrary; newCode.push_Value=(pEntryPoint + offsetof(INJECT_CODE,szDLL));// 将硬代码写入目标进程的入口// 修改内存属性DWORD dwNewFlg, dwOldFlg; dwNewFlg = PAGE_READWRITE;VirtualProtectEx(m_proInfo.hProcess, (LPVOID)pEntryPoint, sizeof(DWORD), dwNewFlg, &dwOldFlg);WriteProcessMemory(m_proInfo.hProcess, pEntryPoint, &newCode, sizeof(newCode), NULL);//&dwWrited); VirtualProtectEx(proInfo.hProcess, (LPVOID)pEntryPoint, sizeof(DWORD), dwOldFlg, &dwNewFlg);// 释放FileMaping 注意,不是Closehandle(hMap)UnmapViewOfFile(lpMap);// 继续目标进程的运行/*
第五步:用ResumeThread运行目标进程。ResumeThread(m_proInfo.hThread); 在监视进程中就结束了自己的任务,剩下的第6,7,8步就需要在Dll的DllMain中进行配合。DLL中用来保存数据的结构体
*/
typedef struct{ DWORD lpEntryPoint; DWORD OldAddr; DWORD OldCode[4];}JMP_CODE,* LPJMP_CODE; static JMP_CODE _lpCode; // 在DllMain的DLL_PROCESS_ATTACH中调用InitApiSpy函数// 在该函数中实现第6,7,8步
/*
第六步:目标进程就运行了LoadLibrary(MyDll),实现DLL的注入。
*/int WINAPI DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved){ switch(dwReason) { case DLL_PROCESS_ATTACH: return InitApiSpy();……// InitApiSpy函数的实现BOOL WINAPI InitApiSpy(){ HANDLE hMap; LPSPY_MEM_SHARE lpMem; DWORD dwSize; BOOL rc; BYTE* lpByte; // 取得FileMapping的句柄 hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, “MyDllMapView”); if(hMap) { lpMem = (LPSPY_MEM_SHARE)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); if(lpMem) {//第七步:目标进程运行完LoadLibrary(MyDll)后,将原来的代码写回目标进程的入口。 // 恢复目标进程的入口代码// 得到mov eax, value代码的地址 _lpCode.OldAddr = (DWORD)((BYTE*)lpMem->lpEntryPoint + offsetof(INJECT_CODE, jmp_MOVEAX)); _lpCode.lpEntryPoint = (DWORD)lpMem->lpEntryPoint; // 保存LoadLibrary()后面的代码 memcpy(&_lpCode.OldCode, (BYTE*)lpMem->oldcode + offsetof(INJECT_CODE, jmp_MOVEAX), 2*sizeof(DWORD)); // 恢复目标进程的入口代码 rc = WriteProcessMemory(GetCurrentProcess(), lpMem->lpEntryPoint, lpMem->oldcode, sizeof(INJECT_CODE), &dwSize); lpByte = (BYTE*)lpMem->lpEntryPoint + offsetof(INJECT_CODE, jmp_MOVEAX); UnmapViewOfFile(lpMem); } CloseHandle(hMap); } // 实现自己Dll的其他功能,如导入表的替换// ……// 将LoadLibrary后面的代码写为转入处理程序中// 指令为:mov eax, objAddress// jmp eax { BYTE* lpMovEax; DWORD* lpMovEaxValu; WORD* lpJmp; DWORD fNew, fOld; fNew = PAGE_READWRITE; lpMovEax = lpByte; VirtualProtect(lpMovEax, 2*sizeof(DWORD), fNew, &fOld); *lpMovEax = 0xB8; lpMovEaxValu = (DWORD*)(lpMovEax + 1); *lpMovEaxValu = (DWORD)&DoJmpEntryPoint; lpJmp = (WORD*)(lpMovEax + 5); *lpJmp = 0xE0FF; // (FF E0) VirtualProtect(lpMovEax, 2*sizeof(DWORD), fOld, &fNew); } return TRUE;} // 转入处理程序DWORD* lpMovEax;DWORD fNew, fOld; void __declspec(naked) DoJmpEntryPoint (){ // 恢复LoadLibrary后面的代码 _gfNew = PAGE_READWRITE; _glpMovEax = (DWORD*)_lpCode.OldAddr; VirtualProtect(_glpMovEax, 2*sizeof(DWORD), _gfNew, &_gfOld); *_glpMovEax = _lpCode.OldCode[0]; *(_glpMovEax + 1) = _lpCode.OldCode[1]; VirtualProtect(_glpMovEax, 2*sizeof(DWORD), _gfOld, &_gfNew);//第八步:目标进程Jmp至原来的入口,继续运行程序。// 跳至目标代码的入口 _asm popad _asm jmp _lpCode.lpEntryPoint}
DLL注入方式有多种,你说的方法是通过子进程的方式注入DLL,我问的是通过调试进程方式注入DLL,在《WINDOWS核心编程》中,我就这种没测试成功啊。:-(
晕,错别字太多!有哪位朋友给个提示也好,注入过程中,好像是目标进程的新EIP没有设置成功。调试过程不好调,这又涉及到如何查看调试进程中指令指针位置的正确性,以及其目标代码注入的成功与否。
BOOL EnablePrivilege(char *PrivilegeName,BOOL IsEnable)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid; if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES |
TOKEN_QUERY | TOKEN_READ,&hToken))
{
return FALSE;
} if(!LookupPrivilegeValue(NULL, PrivilegeName, &luid))
{
return TRUE;
} tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = (IsEnable) ? SE_PRIVILEGE_ENABLED : 0; AdjustTokenPrivileges(hToken,FALSE,&tp,NULL,NULL,NULL); CloseHandle(hToken); return (GetLastError() == ERROR_SUCCESS);
}DWORD GetProcessIdByName(LPCTSTR lpStrName)
{
HANDLE hSnapShot;
PROCESSENTRY32 pe={sizeof(pe)};
hSnapShot=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
for(BOOL fok=::Process32First(hSnapShot,&pe); fok ;fok=::Process32Next(hSnapShot,&pe))
{
if(lstrcmpi(pe.szExeFile , lpStrName) == 0)
{
return pe.th32ProcessID;
}
}
return -1;
}
//inject dll to process,szDllPath is full path!
bool InjectDllToRemoteProcess(DWORD dwProcessId,LPCSTR szDllPath)
{
HANDLE hRemoteProcess=NULL; //remote process will be injected
HANDLE hRemoteThread=NULL; //injected thread!
DWORD dwThreadSize=0; PVOID pRemoteThread=NULL; //remote thread start pointer
PVOID pRemoteParam=NULL; //remote thread thread param!
DWORD dwWriten=0;
BOOL bRet=FALSE; CHAR szDllPathCopy[1024]="";
lstrcpy(szDllPathCopy,szDllPath); EnablePrivilege(SE_DEBUG_NAME,true);//up Privilege hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS,false,dwProcessId);
if(hRemoteProcess == NULL)
{
USR_IMPORTANT("open process error!");
return false;
}
//alloc remote param memory,1024 byte for store the dll path!
pRemoteParam = VirtualAllocEx(hRemoteProcess,NULL,1024,MEM_COMMIT,PAGE_READWRITE);
if(pRemoteParam == NULL)
{
USR_IMPORTANT("faild to alloc memory");
return false;
}
//write the dll path to remote memory
bRet = WriteProcessMemory(hRemoteProcess,pRemoteParam,(LPVOID)szDllPathCopy,1024,&dwWriten); //write param to remote alloced space!
if(!bRet)
{
USR_IMPORTANT("faild to write memory");
return false;
}
//get the loadlibraryA's pointer!
pRemoteThread = GetProcAddress(LoadLibrary("kernel32.dll"),"LoadLibraryA"); //here must be "LoadLibraryA"!!
if(pRemoteThread == NULL)
{
USR_IMPORTANT("faild to get loadlibraryA address!");
return false;
}
//start the thread!
hRemoteThread = CreateRemoteThread(hRemoteProcess,0,0,(DWORD(__stdcall *)(VOID*))pRemoteThread,pRemoteParam,0,&dwWriten); EnablePrivilege(SE_DEBUG_NAME,false); //down Privilege return true;
}
你的dll提供一个exec接口。参数就是对方进程的名字。
在exec里面调用上面的接口注入进去。
直接rundll32 你的dllname.dll,exec 对方进程名
就可以了。不用再写个exe调用。并且可以直接调试。相当方便。
pid是你的目标程序的进程id
Inject Dll Path是你要注入的dll建议你查查调试器的Attach做了哪些事情.或者找个调试器的源码瞧瞧.
//
BOOL InjectLibrary(HANDLE hProcess,
HANDLE hThread,
PBYTE pfLoadLibrary,
PBYTE pbData,
DWORD cbData)
{
BOOL fSucceeded = FALSE;
DWORD nProtect = 0;
DWORD nWritten = 0;
CONTEXT cxt;
UINT32 nCodeBase;
PBYTE pbCode; struct Code
{
BYTE rbCode[128];
union
{
WCHAR wzLibFile[512];
CHAR szLibFile[512];
};
} code; SuspendThread(hThread);
ZeroMemory(&cxt, sizeof(cxt));
cxt.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext(hThread, &cxt)) {
goto finish;
}#if VERBOSE
printf(" ContextFlags: %08x\n", cxt.ContextFlags);
printf(" EIP=%04x:%08x ESP=%04x:%08x EBP=%08x\n",
cxt.SegCs & 0xffff, cxt.Eip, cxt.SegSs & 0xffff, cxt.Esp, cxt.Ebp);
printf(" DS=%04x ES=%04x FS=%04x GS=%04x EFL=%08x\n",
cxt.SegDs & 0xffff, cxt.SegEs & 0xffff,
cxt.SegFs & 0xffff, cxt.SegGs & 0xffff,
cxt.EFlags);
printf(" EAX=%08x EBX=%08x ECX=%08x EDX=%08x ESI=%08x EDI=%08x\n",
cxt.Eax, cxt.Ebx, cxt.Ecx, cxt.Edx, cxt.Esi, cxt.Edi);
#endif nCodeBase = (cxt.Esp - sizeof(code)) & ~0x1fu; // Cache-line align.
pbCode = code.rbCode; if (pbData) {
CopyMemory(code.szLibFile, pbData, cbData);
pbCode = DetourGenPush(pbCode, nCodeBase + offsetof(Code, szLibFile));
pbCode = DetourGenCall(pbCode, pfLoadLibrary,
(PBYTE)nCodeBase + (pbCode - code.rbCode));
}
pbCode = DetourGenMovEax(pbCode, cxt.Eax);
pbCode = DetourGenMovEbx(pbCode, cxt.Ebx);
pbCode = DetourGenMovEcx(pbCode, cxt.Ecx);
pbCode = DetourGenMovEdx(pbCode, cxt.Edx);
pbCode = DetourGenMovEsi(pbCode, cxt.Esi);
pbCode = DetourGenMovEdi(pbCode, cxt.Edi);
pbCode = DetourGenMovEbp(pbCode, cxt.Ebp);
pbCode = DetourGenMovEsp(pbCode, cxt.Esp);
pbCode = DetourGenJmp(pbCode, (PBYTE)cxt.Eip,
(PBYTE)nCodeBase + (pbCode - code.rbCode));
cxt.Esp = nCodeBase - 4;
cxt.Eip = nCodeBase; if (!VirtualProtectEx(hProcess, (PBYTE)nCodeBase, sizeof(Code),
PAGE_EXECUTE_READWRITE, &nProtect)) {
goto finish;
}#if VERBOSE
printf("VirtualProtectEx(%08x) -> %d\n", nProtect, b);
#endif if (!WriteProcessMemory(hProcess, (PBYTE)nCodeBase, &code, sizeof(Code),
&nWritten)) {
goto finish;
}#if VERBOSE
printf("code: %08x..%08x (WriteProcess: %d)\n",
nCodeBase, nCodeBase + (pbCode - code.rbCode), nWritten);
#endif
if (!FlushInstructionCache(hProcess, (PBYTE)nCodeBase, sizeof(Code))) {
goto finish;
}
if (!SetThreadContext(hThread, &cxt)) {
goto finish;
}#if VERBOSE
ZeroMemory(&cxt, sizeof(cxt));
cxt.ContextFlags = CONTEXT_FULL;
b = GetThreadContext(hThread, &cxt);
printf(" EIP=%04x:%08x ESP=%04x:%08x EBP=%08x\n",
cxt.SegCs & 0xffff, cxt.Eip, cxt.SegSs & 0xffff, cxt.Esp, cxt.Ebp);
printf(" DS=%04x ES=%04x FS=%04x GS=%04x EFL=%08x\n",
cxt.SegDs & 0xffff, cxt.SegEs & 0xffff,
cxt.SegFs & 0xffff, cxt.SegGs & 0xffff,
cxt.EFlags);
printf(" EAX=%08x EBX=%08x ECX=%08x EDX=%08x ESI=%08x EDI=%08x\n",
cxt.Eax, cxt.Ebx, cxt.Ecx, cxt.Edx, cxt.Esi, cxt.Edi);
#endif
fSucceeded = TRUE;
finish:
ResumeThread(hThread);
return fSucceeded;
}/////////////////////////////////////////////////////////////// Injected Code.
//
#pragma check_stack(off)
#pragma pack(push, 8)typedef HINSTANCE (WINAPI *PROCLOADLIBRARY)(PWCHAR);typedef struct {
PROCLOADLIBRARY fnLoadLibrary;
WCHAR wzLibFile[MAX_PATH];
} INJLIBINFO, *PINJLIBINFO;// Calls to the stack-checking routine must be disabled.static DWORD WINAPI ThreadFunc(PINJLIBINFO pInjLibInfo) {
// There must be less than a page-worth of local
// variables used in this function.
HINSTANCE hinstLib; // Call LoadLibrary(A/W) to load the DLL.
hinstLib = pInjLibInfo->fnLoadLibrary(pInjLibInfo->wzLibFile);
return((DWORD) hinstLib);
}#pragma warning(disable: 4702)static DWORD WINAPI DeadThreadFunc(PINJLIBINFO pInjLibInfo)
{
(void)pInjLibInfo;
x:
goto x;
return 0;
}// This function s the memory address after ThreadFunc.
// ThreadFuncCodeSizeInBytes = (PBYTE) AfterThreadFunc - (PBYTE) ThreadFunc.
static void AfterThreadFunc (void) {
}#pragma pack(pop)
#pragma check_stack
修改导入表 没用过,这个应该是目标启动前修改的吧?
Section映射 这个完全不懂。。 欢迎讲解。。
Detours V2.1有导入表注入的示例Section映射这个讲起来就烦一点(这称呼是我自己叫的,学名未必叫这个),很抱歉没什么耐心去敲一大段文字。你可以先去学习一下内核关于进程和Dll加载的资料。我记得网上似乎有LdrLoadDll的源码(也许是伪代码)。把Dll加载过程理解了,基本上你就知道怎么弄了。
这样看来Section映射 似乎最牛X了
谢谢你提供的信息,我测试一下。
解决方案记录在:http://blog.csdn.net/yuzl32/archive/2010/02/24/5323489.aspx中的条目5。