在《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);
}
}

解决方案 »

  1.   

    你这代码叫人怎么检查,除非给你调。
    思路检查下,正确就OK。对照其实只要单步的话,就能定位出问题所在了。
    Java的老兄,VC的IDE还用的惯吧?
      

  2.   

    懒得帮人调试,我要睡觉去了。代码自己拿去对照吧,你的代码我也没细看,从硬盘里拖了个出来,应该是你要的吧1.  用CreateProcess(CREATE_SUSPENDED)启动目标进程。2.  找到目标进程的入口,用ImageHlp中的函数可以实现。3.  将目标进程入口的代码保存起来。4.  在目标进程的入口写入LoadLibrary(MyDll)实现Dll的注入。5.  用ResumeThread运行目标进程。6.  目标进程就运行了LoadLibrary(MyDll),实现DLL的注入。7.  目标进程运行完LoadLibrary(MyDll)后,将原来的代码写回目标进程的入口。8.  目标进程Jmp至原来的入口,继续运行程序。从原理上可以看出,DLL的注入在目标进程的开始就运行了,而且不是用Debug的方案,这样,就没有上面方案的局限性了。该方案的关键在6,7,8三步,实现方法需要监视进程和DLL合作。下面,结合代码进行分析。在监视进程中,创建FileMapping,用来保存目标进程的入口代码,同时保证DLL中可以访问。在第7步实现将原目标代码写回目标进程的入口。// 监视程序和DLL共用的结构体#pragma pack (push ,1)  // 保证下面的结构体采用BYTE对齐(必须)typedef struct {       BYTE      int_PUSHAD;         // pushad        0x60              BYTE      int_PUSH;             // push &szDLL     0x68       DWORD push_Value;           //            &szDLL = "ApiSpy.dll"的path       BYTE      int_MOVEAX;              //  move eax &LoadLibrary  0xB8       DWORD eax_Value;             //     &LoadLibrary       WORD    call_eax;         //     call eax    0xD0FF(FF D0) (LoadLibrary("ApiSpy.dll");       BYTE      jmp_MOVEAX;             //     move eax &ReplaceOldCode  0xB8              DWORD jmp_Value;             //     JMP的参数       WORD    jmp_eax;        //     jmp eax   0xE0FF(FF E0) jmp ReplaceOldCode;       char szDLL[MAX_PATH]; //  "ApiSpy.dll"的FullPath}INJECT_LOADLIBRARY_CODE, *LPINJECT_CODE; #pragma pack (pop , 1)//上面结构体的代码为汇编代码,对应的汇编为:
    /*
    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}
      

  3.   


    DLL注入方式有多种,你说的方法是通过子进程的方式注入DLL,我问的是通过调试进程方式注入DLL,在《WINDOWS核心编程》中,我就这种没测试成功啊。:-(
      

  4.   

    好的,期待!!有哪位朋友给个提示也好,注入过程中,好像是目标进程的新EIP没有设置成功。调试调试不好调,这又涉及到如何查看调试进程中指令指针位置的正确性,已经其目标代码注入的成功与否。
      

  5.   


    晕,错别字太多!有哪位朋友给个提示也好,注入过程中,好像是目标进程的新EIP没有设置成功。调试过程不好调,这又涉及到如何查看调试进程中指令指针位置的正确性,以及其目标代码注入的成功与否。
      

  6.   

    //Enable Privilege for inject!
    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调用。并且可以直接调试。相当方便。
      

  7.   

    谢谢你的关注!你这个的注入方式是通过远程线程的方式,我想了解的是调试进程注入DLL的方式。:-(
      

  8.   

    printf("Usage:InjDebuggee.exe <PID> <Be Inject Dll Path>");    根据你的参数, 猜测你应该是先启动某程序。再取得该pid。那你是如何变成被调试进程的父进程的?就是上面这个:而且调试程序与它的被调试程序之间必须存在固定的关系。
      

  9.   

    InjDebuggee.exe 是你的注入程序 相当于调试器
    pid是你的目标程序的进程id
    Inject Dll Path是你要注入的dll建议你查查调试器的Attach做了哪些事情.或者找个调试器的源码瞧瞧.
      

  10.   

    可能我就是这个方面不是很清楚,才找不到问题的所在。DebugActiveProcess在MSDN中似乎也没有特别的说明。我用CreateProcess方式调试目标进程也无法注入DLL。(见源程序中的CreateProcess注释行。)
      

  11.   

    Detours V1.5版本有使用调试注入的示例代码:你去下载跟踪一下即可。我附上部分代码来证明它的存在:
    //
    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 
      

  12.   

    从全局钩子、远线程、调试注入、修改导入表、APC注入、Section映射注入的手法是越来越多了。还有手段欢迎补充
      

  13.   

    APC注入....   原来还可以这样
    修改导入表  没用过,这个应该是目标启动前修改的吧?
    Section映射   这个完全不懂。。 欢迎讲解。。
      

  14.   

    Detours V1.5版本有远线程、调试注入的示例
    Detours V2.1有导入表注入的示例Section映射这个讲起来就烦一点(这称呼是我自己叫的,学名未必叫这个),很抱歉没什么耐心去敲一大段文字。你可以先去学习一下内核关于进程和Dll加载的资料。我记得网上似乎有LdrLoadDll的源码(也许是伪代码)。把Dll加载过程理解了,基本上你就知道怎么弄了。
      

  15.   

    ...好的
    这样看来Section映射 似乎最牛X了
      

  16.   

    to wangk
    谢谢你提供的信息,我测试一下。
      

  17.   

    今天把之前放下的这个问题再重新审视了一下,结果就解决了!:-) 谢谢各位提供的信息。
    解决方案记录在:http://blog.csdn.net/yuzl32/archive/2010/02/24/5323489.aspx中的条目5。