15,471
社区成员
发帖
与我相关
我的任务
分享
#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 int3
typedef 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);
}
}
//
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 marks the memory address after ThreadFunc.
// ThreadFuncCodeSizeInBytes = (PBYTE) AfterThreadFunc - (PBYTE) ThreadFunc.
static void AfterThreadFunc (void) {
}
#pragma pack(pop)
#pragma check_stack
// 监视程序和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)
//上面结构体的代码为汇编代码,对应的汇编为:
/*
pushad
push szDll
mov eax, &LoadLibraryA
call eax // 实现调用LoadLibrary(szDll)的代码
mov eax, oldentry
jmp 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;
}
// 创建FileMapping
hMap = 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
}