由於本人也是新手,如果有朋友不懂windows api相關知識,我相信查閱書籍或者百度會比我說有幫助的多,下面就我所做簡單復述一下過程,歡迎指正缺點。
效果圖示如下:
做的這個例子首先是創建了一個MFC 對話框程序,然后自己創建了一個 帶有導出函數 (簡單的減法) 的DLL , 這個Calc按鍵就是調用自己DLL里面的減法函數 計算1 - 1, 其次創建一個擁有能夠修改進程中某函數的入口代碼功能的DLL(為什么是DLL,網上有大量詳細的資料,), 然后我們還創建一個windows控制台程序 也就是 調用CreateRemoteThread 讓Calc 加載我們准備好的DLL(修改函數入口代碼), 因為DLL被加載時我們可以在DLLMain中指定要執行的代碼。
未注入代碼之前:
執行我的 注入程序createremotethread.exe 之后 如下圖:
可以看到注入成功了, 注入的是什么呢? 這就是 CreateRemoteThread的作用了, 我們向Calc.exe 注入了一個線程,然后這個線程執行了LoadLibrary 函數,
我告訴Calc 要Load 我指定的 DLL, 為什么呢? 因為 我指定的這個DLL 是我們自己創建的, 它里面的函數代碼能找到Calc進程中 原來sub函數的地址,然后並
修改sub函數地址處的入口代碼,也就是改成 jmp xxx 使Calc 執行我們指定的代碼。
最重要的CreateRemoteThread:
HANDLE hThread; char szLibPath[_MAX_PATH] = "E:\\vs2010project\\InjectDll\\Release\\InjectDll.dll"; //指定注入之后目標進程要加載的DLL DWORD hLibModule; HANDLE hProcess = NULL; hProcess = GetProcessByName("Calc.exe"); DWORD ERRO = GetLastError(); if(hProcess == NULL) return 0; HMODULE modHandle = GetModuleHandle(_T("Kernel32")); //因為kernel32 每一個windows程序進程空間中都有 所以讓他調用LOADLIBRARY不成問題 void* pLibRemote = VirtualAllocEx(hProcess, NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_EXECUTE_READWRITE); LPTHREAD_START_ROUTINE addr = (LPTHREAD_START_ROUTINE)GetProcAddress(modHandle, "LoadLibraryA"); WriteProcessMemory( hProcess, pLibRemote, (void*)szLibPath, sizeof(szLibPath), NULL); hThread = CreateRemoteThread(hProcess, NULL, 0, addr, pLibRemote, 0, NULL); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread);
根據進程名字獲取進程句柄也是本例子非常關鍵的部分,可以通過微軟提供的api 拍攝進程列表快照, 然后再遍歷尋找,代碼如下:
HANDLE GetProcessByName(const char* name) { EnableDebugPriv(); DWORD pid = 0; HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 process; ZeroMemory(&process, sizeof(process)); process.dwSize = sizeof(process); if (Process32First(snapshot, &process)) { do { if( stricmp(UnicodeToAnsi(process.szExeFile), name) == 0) { pid = process.th32ProcessID; break; } }while(Process32Next(snapshot, &process)); } CloseHandle(snapshot); if(pid != 0) { HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); return hProcess; } return NULL; }
其中 關於 CreateRemoteThread 部分的核心代碼有許多需要注意的事情 主要有 執行OPENPROCESS之前需要開啟特權 代碼如下:
1 void EnableDebugPriv() 2 { 3 HANDLE hToken; 4 LUID luid; 5 TOKEN_PRIVILEGES tkp; 6 7 OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); 8 9 LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid); 10 11 tkp.PrivilegeCount = 1; 12 tkp.Privileges[0].Luid = luid; 13 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 14 15 AdjustTokenPrivileges(hToken, false, &tkp, sizeof(tkp), NULL, NULL); 16 17 CloseHandle(hToken); 18 }
接下來我們就可以調用openprocess 打開目標進程 進行進一步的操作(調用CreateRemoteThread)達到使目標進程加載我們指定DLL,進而指定DLL被加載時能執行指定代碼。
最后 關於修改進程中 導入 dll 中的函數的入口處代碼 的代碼如下:
BYTE NewCode[5]; //用來替換原入口代碼的字節 (jmp xxxx) typedef int (_cdecl* getsub)(int x,int y); //typedef 比較少的用法 能定一個函數指針類型 即getsub getsub mySub = NULL; //用新定義的類型定義一個變量 FARPROC pfar_sub; //指向mySub函數的遠指針 HANDLE hProcess = NULL; //所處進程的句柄 DWORD pid; //所處進程ID
//修改mySub入口處代碼 void modify() { assert(hProcess != NULL); DWORD dwTemp=0; DWORD dwOldProtect; VirtualProtectEx(hProcess, pfar_sub, 5, PAGE_READWRITE, &dwOldProtect); //將內存保護模式改為可讀寫,原保護模式保存入dwOldProtect WriteProcessMemory(hProcess, pfar_sub, NewCode, 5, 0); VirtualProtectEx(hProcess, pfar_sub, 5, dwOldProtect, &dwTemp); //恢復內存保護模式 } int new_sub(int x,int y) { return 1; } int inject() { DWORD dwPid = ::GetCurrentProcessId(); hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPid); int addr_farpointer = 0; //獲取My_sub()函數地址 HMODULE hmod = ::LoadLibrary(_T("E:\\vs2010project\\My_Sub\\Debug\\My_Sub.dll")); mySub = (getsub)::GetProcAddress(hmod, "mySub"); pfar_sub=(FARPROC)mySub; addr_farpointer = (int)pfar_sub; if (pfar_sub == NULL) { MessageBox(NULL, TEXT("locate mySub failed!!"), TEXT("info"), MB_OK); return FALSE; } NewCode[0] = 0xe9;//0xe9 == jmp _asm { lea eax, new_sub mov ebx, pfar_sub sub eax, ebx sub eax, 5 mov dword ptr [NewCode + 1],eax } modify(); MessageBox(NULL, TEXT("Modified SUCCESSFULLY!!"), TEXT("info"), MB_OK); return TRUE; }
整體流程清楚了實踐應該沒啥問題(還是需要折騰的, 折騰也是進步的過程)。
附上主要工程文件鏈接 http://pan.baidu.com/s/1dD4WhZN