1.openprocess:打开对应进程,获得句柄
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | // Required by Alpha
PROCESS_CREATE_THREAD | // For CreateRemoteThread
PROCESS_VM_OPERATION | // For VirtualAllocEx/VirtualFreeEx
PROCESS_VM_WRITE, // For WriteProcessMemory
FALSE, dwPid);
其中dwpid表示对应进程的pid值
2.创建内存空间
currentAddress = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1024); //类似于自己管理堆栈分配。
//GetProcessHeap():返回进程默认堆句柄
if (NULL == currentAddress)
{
nRet = Error_HeapAlloc;
break;
}
3.分配虚拟内存空间
targetWorkspace = VirtualAllocEx(hProcess, 0, 1024, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); //在进程的虚拟空间保留或提交内存区域,返回值为分配区域的地址
//判断分配是否成功
if (NULL == targetWorkspace)
{
nRet = Error_VirtualAllocEx;
break;
}
DWORD targetAddress = PtrToUlong(targetWorkspace); //PtrToUlong:指针转dword:unsigned long类型
4.准备机器代码,然后获取系统函数的地址,用来调用:
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
FARPROC loadlibrary = GetProcAddress(kernel32, bLoadDll ? "LoadLibraryA" : "GetModuleHandleA");//GetModuleHandle:获取一个应用程序或动态链接库的模块句柄。只有在当前进程的场景中,这个句柄才会有效。
FARPROC getprocaddress = GetProcAddress(kernel32, "GetProcAddress"); //获得DLL的指定函数地址
FARPROC exitthread = GetProcAddress(kernel32, "ExitThread");
FARPROC freelibraryandexitthread = GetProcAddress(kernel32, "FreeLibraryAndExitThread");
5.填充字符串,并且保存真正的代码开始位置:
// 索引
DWORD currentIdx = 0;
DWORD dwTmp = 0;
// 4.2. 填充三个指针空间
size_t sizePtr = sizeof(int*);
const size_t addressCount = 3;
for (size_t i = 0 ; i < addressCount * sizePtr; i++)
{
currentAddress[i] = 0x00; //分配字节;(空字节)
}
currentIdx += addressCount * sizePtr; // 推进索引
DWORD user32Addr = targetAddress + 0; // 存放User32.dll的模块地址
DWORD msgboxAddr = targetAddress + 4; // 存放User32.dll中MessageBoxA的模块地址
DWORD injectDllAddr = targetAddress + 8; // 存放待注入的dll的加载地址
// 4.3. 填充字符串
char user32Name[MAX_PATH + 1] = {0};
char msgboxName[MAX_PATH + 1] = {0};
char injectDllName[MAX_PATH + 1] = {0};
char injectFuncName[MAX_PATH + 1] = {0};
char injectParam[MAX_PATH*2 + 1] = {0};
char injectErrorTitle[MAX_PATH + 1] = {0};
char injectErrorMsg1[MAX_PATH + 1] = {0};
char injectErrorMsg2[MAX_PATH + 1] = {0};
_snprintf_s(injectDllName, MAX_PATH, MAX_PATH-1, "%s", dllname);//格式化字符串
_snprintf_s(injectFuncName, MAX_PATH, MAX_PATH-1, "%s", funcname);
_snprintf_s(injectParam, MAX_PATH*2, MAX_PATH*2-1, "%s", param);
_snprintf_s(user32Name, MAX_PATH, MAX_PATH-1, "user32.dll");
_snprintf_s(msgboxName, MAX_PATH, MAX_PATH-1, "MessageBoxA");
_snprintf_s(injectErrorTitle, MAX_PATH, MAX_PATH-1, "Error");
_snprintf_s(injectErrorMsg1, MAX_PATH, MAX_PATH-1, "Could not load the dll: %s", injectDllName);
_snprintf_s(injectErrorMsg2, MAX_PATH, MAX_PATH-1, "Could not load the function: %s", injectFuncName);
DWORD user32NameAddr = 0;
DWORD msgboxNameAddr = 0;
DWORD injectDllNameAddr = 0;
DWORD injectFuncNameAddr = 0;
DWORD injectParamAddr = 0;
DWORD injectErrorTitleAddr = 0;
DWORD injectErrorMsg1Addr = 0;
DWORD injectErrorMsg2Addr = 0;
FillInString(user32NameAddr, user32Name)
FillInString(msgboxNameAddr, msgboxName)
FillInString(injectDllNameAddr, injectDllName)
FillInString(injectFuncNameAddr, injectFuncName)
FillInString(injectParamAddr, injectParam)
FillInString(injectErrorTitleAddr, injectErrorTitle)
FillInString(injectErrorMsg1Addr, injectErrorMsg1)
FillInString(injectErrorMsg2Addr, injectErrorMsg2)
// 4.4. 填充一些int3来分隔字符串区和代码区
const size_t int3_count = 3;
for (size_t i = 0 ; i < int3_count; i++)
{
currentAddress[currentIdx++] = 0xCC;
}
// 4.5 保存真正的代码开始位置
DWORD targetExcuteCodeAddress = targetAddress + currentIdx;
6.修正代码区,并且提高权限,使得可以对内存区进行读写。
// 4.6. 修正代码区
memcpy(injectCode_Head_NoSilent + 1, &user32NameAddr, 4);
memcpy(injectCode_Head_NoSilent + 6, &loadlibrary, 4);
memcpy(injectCode_Head_NoSilent + 13, &msgboxNameAddr, 4);
memcpy(injectCode_Head_NoSilent + 19, &getprocaddress, 4);
memcpy(injectCode_Head_NoSilent + 26, &msgboxAddr, 4);
memcpy(injectCode_Head_NoSilent + 31, &injectDllNameAddr, 4);
memcpy(injectCode_Head_NoSilent + 36, &loadlibrary, 4);
memcpy(injectCode_Head_NoSilent + 50, &injectErrorTitleAddr, 4);
memcpy(injectCode_Head_NoSilent + 55, &injectErrorMsg1Addr, 4);
memcpy(injectCode_Head_NoSilent + 62, &msgboxAddr, 4);
memcpy(injectCode_Head_NoSilent + 71, &exitthread, 4);
memcpy(injectCode_Head_NoSilent + 78, &injectDllAddr, 4);
memcpy(injectCode_Head_NoSilent + 83, &injectFuncNameAddr, 4);
memcpy(injectCode_Head_NoSilent + 89, &getprocaddress, 4);
memcpy(injectCode_Head_NoSilent + 103, &injectErrorTitleAddr, 4);
memcpy(injectCode_Head_NoSilent + 108, &injectErrorMsg2Addr, 4);
memcpy(injectCode_Head_NoSilent + 115, &msgboxAddr, 4);
memcpy(injectCode_Head_NoSilent + 124, &exitthread, 4);
memcpy(injectCode_Head_NoSilent + 129, &injectParamAddr, 4);
memcpy(currentAddress + currentIdx, injectCode_Head_NoSilent ,sizeof(injectCode_Head_NoSilent));
currentIdx += sizeof(injectCode_Head_NoSilent);
if (bUnloadDll)
{
memcpy(injectCode_Tail_FreeLibraryAndET + 4, &injectDllAddr, 4);
memcpy(injectCode_Tail_FreeLibraryAndET + 9, &freelibraryandexitthread, 4);
memcpy(currentAddress + currentIdx, injectCode_Tail_FreeLibraryAndET ,sizeof(injectCode_Tail_FreeLibraryAndET));
currentIdx += sizeof(injectCode_Tail_FreeLibraryAndET);
}
else
{
memcpy(injectCode_Tail_ExitThread + 3, &exitthread, 4);
memcpy(currentAddress + currentIdx, injectCode_Tail_ExitThread ,sizeof(injectCode_Tail_ExitThread));
currentIdx += sizeof(injectCode_Tail_ExitThread);
}
// Step5. Change page protection so we can write executable code
DWORD oldProtect = 0;
VirtualProtectEx(hProcess, targetWorkspace, currentIdx, PAGE_EXECUTE_READWRITE, &oldProtect);
写入进程内存,并且恢复属性,
// Step6. Write out the patch
DWORD bytesRet = 0;
if (!WriteProcessMemory(hProcess, targetWorkspace, currentAddress, currentIdx, &bytesRet))
{
nRet = Error_WriteProcessMemory;
break;
}
// Step7. Restore page protection
VirtualProtectEx(hProcess, targetWorkspace, currentIdx, oldProtect, &oldProtect);
// Step8. Make sure our changes are written right away
FlushInstructionCache(hProcess, targetWorkspace, currentIdx);
// Step9. Execute the thread now and wait for it to exit, note we execute where the code starts, and not the codecave start
// (since we wrote strings at the start of the codecave) -- NOTE: void* used for VC6 compatibility instead of UlongToPtr
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)((void*)targetExcuteCodeAddress), 0, 0, NULL);
if (NULL == hThread)
{
nRet = Error_CreateRemoteThread;
break;
}
WaitForSingleObject(hThread, INFINITE);
最后结束,关闭句柄等信息:
CloseHandle(hProcess);
CloseHandle(hThread);
if (targetWorkspace)
{
VirtualFreeEx(hProcess, targetWorkspace, 0, MEM_RELEASE);
}
// Free the currentAddress memory
if (currentAddress)
{
HeapFree(GetProcessHeap(), 0, currentAddress);
}