1. 程式人生 > >DLL注入程式碼(C函式)的編寫

DLL注入程式碼(C函式)的編寫



attachdlltoprocess.cpp

// attachdlltoprocess.cpp : Defines the entry point for the application.
//

#include <WINDOWS.H>
#include <TCHAR.H>
#define CODE_SIZE 1024
BYTE remotecode[CODE_SIZE];

//定義被注入程式碼所需引數的結構體
typedef struct REMOTE_INFO
{
	//API 地址
	DWORD ccall_LoadLibraryA;
	DWORD ccall_GetProcAddress;
	DWORD ccall_VirtualFree;
	DWORD ccall_ExitThread;
	DWORD ccall_MessageBoxA;
	//引數地址
	DWORD cdword_rpfun;
	char *csz_dllname;
	char *csz_InitModule;
	char *csz_msgtitle;
	char *csz_msgerrorload;
	char *csz_msgerrorinitmodule;
}REMOTE_INFO, *PREMOTE_INFO;

#define PARAM_START 0x80000000
#define call_LoadLibraryA PARAM_START + 1
#define call_GetProcAddress PARAM_START + 2
#define call_VirtualFree PARAM_START + 3
#define call_ExitThread PARAM_START + 4
#define call_MessageBoxA PARAM_START + 5
#define sz_InitModule PARAM_START + 6
#define sz_dllname PARAM_START + 7
#define sz_msgtitle PARAM_START + 8
#define sz_msgerrorload PARAM_START + 9
#define sz_msgerrorinitmodule PARAM_START + 10
#define dword_rpfun PARAM_START + 11

//在緩衝區code查詢DWORD值finddata,如果找到替換成setdata
int SetPoint(BYTE *code, DWORD finddata, DWORD setdata)
{
	for(int i = 0; i < CODE_SIZE; i++)
	{
		if(*(DWORD*)&code[i] == finddata)
		{//找到了,替換
			*(DWORD*)&code[i] = setdata;
			return TRUE;
		}
	}
	return FALSE;
}

BOOL AttachDllToProcess(HANDLE hprocess, char *szdll)
{
	DWORD codestart, codeend, codesize;
	_asm
	{
		jmp CODE_END;
CODE_START:
		//被注入的程式碼起始地址
		int 3;
		//LoadLibraryA(sz_dllname);
		push sz_dllname;
		mov eax, call_LoadLibraryA;
		call eax;
		test eax, eax;
		jnz GETPROC;
		//MessageBoxA(NULL, "載入[sz_dllname]失敗", "錯誤", MB_OK);
		push MB_OK;
		push sz_msgtitle;
		push sz_msgerrorload;
		push NULL;
		mov eax, call_MessageBoxA;
		call eax;
		jmp CLEAR;
GETPROC:
		push eax;
		push sz_InitModule;
		push eax;
		mov eax, call_GetProcAddress;
		call eax;
		test eax, eax;
		jnz CALLINIT;
		//MessageBoxA(NULL, "獲取函式[InitModule]地址失敗", "錯誤", MB_OK);
		push MB_OK;
		push sz_msgtitle;
		push sz_msgerrorinitmodule;
		push NULL;
		mov eax, call_MessageBoxA;
		call eax;
		jmp CLEAR;
CALLINIT:
		//InitModule(hinstance);
		call eax;
CLEAR:
		//VirtualFree(dword_rpfun, 0, MEM_RELEASE);
		//ExitThread(0);
		//以下程式碼將在堆疊中執行,原因為呼叫VirtualFree後所在的記憶體就無效了
		push 0;
		push MEM_RELEASE;
		push 0;
		push dword_rpfun;
		push call_ExitThread;
		push call_VirtualFree;
		ret;
		//被注入的程式碼結束地址
CODE_END:
		//獲取被注入程式碼的首地址和結束地址
		lea eax, CODE_START;
		mov codestart, eax; 
		lea eax, CODE_END;
		mov codeend, eax;
	}
	codesize = codeend - codestart; //被注入的程式碼長度
	RtlCopyMemory(remotecode, (LPVOID)codestart, codesize); //複製被注入的程式碼到緩衝區
	DWORD dataoffset = codesize;
	DWORD oldprotect, sztmp;
	//在目標程序中申請記憶體
	LPVOID lpcode = VirtualAllocEx(hprocess, NULL, CODE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	DWORD addrlocal = (DWORD)remotecode, addrremote = (DWORD)lpcode;
	//修改緩衝區記憶體屬性為可執行
	VirtualProtectEx(GetCurrentProcess(), remotecode, CODE_SIZE, PAGE_EXECUTE_READWRITE, &oldprotect);

	//修正被注入程式碼的API引數地址
	SetPoint(remotecode, call_LoadLibraryA, (DWORD)LoadLibraryA);
	SetPoint(remotecode, call_GetProcAddress, (DWORD)GetProcAddress);
	SetPoint(remotecode, call_VirtualFree, (DWORD)VirtualFree);
	SetPoint(remotecode, call_ExitThread, (DWORD)ExitThread);
	SetPoint(remotecode, call_MessageBoxA, (DWORD)MessageBoxA);
	SetPoint(remotecode, dword_rpfun, (DWORD)lpcode);
	
	SetPoint(remotecode, sz_dllname, addrremote + dataoffset);
	lstrcpyA((char*)(addrlocal + dataoffset), szdll);
	dataoffset += lstrlenA(szdll) + 1;
	
	SetPoint(remotecode, sz_InitModule, addrremote + dataoffset);
	lstrcpyA((char*)(addrlocal + dataoffset), "InitModule");
	sztmp = addrlocal + dataoffset;
	dataoffset += lstrlenA((char*)(addrlocal + dataoffset)) + 1;
	
	SetPoint(remotecode, sz_msgtitle, addrremote + dataoffset);
	lstrcpyA((char*)(addrlocal + dataoffset), "錯誤");
	dataoffset += lstrlenA((char*)(addrlocal + dataoffset)) + 1;
	
	SetPoint(remotecode, sz_msgerrorload, addrremote + dataoffset);
	wsprintfA((char*)(addrlocal + dataoffset), "載入[%s]失敗", szdll);
	dataoffset += lstrlenA((char*)(addrlocal + dataoffset)) + 1;
	
	SetPoint(remotecode, sz_msgerrorinitmodule, addrremote + dataoffset);
	wsprintfA((char*)(addrlocal + dataoffset), "獲取函式[%s]地址失敗", sztmp);
	dataoffset += lstrlenA((char*)(addrlocal + dataoffset)) + 1;
	
	WriteProcessMemory(hprocess, lpcode, remotecode, CODE_SIZE, &oldprotect);
	/*
	_asm
	{
		mov eax, lpcode;
		jmp eax;
	}
	*/
	CreateRemoteThread(hprocess, NULL, NULL, (LPTHREAD_START_ROUTINE)lpcode, 0, NULL, NULL);
	return TRUE;
}

//被注入到遠端程序的C函式
DWORD WINAPI RemoteCode(PREMOTE_INFO pri)
{
	DWORD codeend;
	//LoadLibraryA;
	if(pri->cdword_rpfun)
	{
		//_asm int 3;
		typedef HMODULE (WINAPI *tLoadLibraryA)(LPCSTR lpLibFileName);
		tLoadLibraryA sysLoadLibraryA;
		sysLoadLibraryA = (tLoadLibraryA)pri->ccall_LoadLibraryA;
		HMODULE hmodule = sysLoadLibraryA(pri->csz_dllname);//載入DLL
		typedef int (WINAPI *tMessageBoxA)(HWND hWnd , LPCSTR lpText, LPCSTR lpCaption, UINT uType);
		tMessageBoxA sysMessageBoxA;
		sysMessageBoxA = (tMessageBoxA)pri->ccall_MessageBoxA;
		DWORD rpfun = pri->cdword_rpfun;
		DWORD ccall_ExitThread = pri->ccall_ExitThread;
		DWORD ccall_VirtualFree = pri->ccall_VirtualFree;
		if(NULL != hmodule)
		{
			typedef FARPROC (WINAPI *tGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
			tGetProcAddress sysGetProcAddress;
			sysGetProcAddress = (tGetProcAddress)pri->ccall_GetProcAddress;
			FARPROC pinitmodule = (FARPROC)sysGetProcAddress(hmodule, pri->csz_InitModule);
			if(NULL != pinitmodule)
			{//呼叫InitModule
				typedef void (WINAPI *tInitModule)(HMODULE hModule);
				tInitModule sysInitModule;
				sysInitModule = (tInitModule)pinitmodule;
				sysInitModule(hmodule);
			}
			else
			{//獲取InitModule失敗
				sysMessageBoxA(NULL, pri->csz_msgerrorinitmodule, pri->csz_msgtitle, MB_OK);
			}
		}
		else
		{//載入DLL失敗
			sysMessageBoxA(NULL, pri->csz_msgerrorload, pri->csz_msgtitle, MB_OK);
		}
		_asm
		{//釋放記憶體,退出執行緒
			push 0;
			push MEM_RELEASE;
			push 0;
			push rpfun;
			push ccall_ExitThread;
			push ccall_VirtualFree;
			ret;
		}
	}
	_asm
	{
		call GET_ENDADDR;
GET_ENDADDR:
		pop codeend;
	}
	codeend += 50;
	return codeend;
}

BOOL AttachDllToProcessC(HANDLE hprocess, char *szdll)
{
	DWORD codestart, codeend, codesize;
	PREMOTE_INFO pri = (PREMOTE_INFO)remotecode;

	if(0xe9 == *(BYTE*)RemoteCode)
	{
		codestart = (DWORD)RemoteCode + *(DWORD*)((DWORD)RemoteCode + 1) + 5;
	}
	else
		codestart = (DWORD)RemoteCode;
	RtlZeroMemory(remotecode, CODE_SIZE);
	codeend = RemoteCode(pri);
	codesize = codeend - codestart; //被注入的程式碼長度
	pri = (PREMOTE_INFO)&remotecode[codesize];
	RtlCopyMemory(remotecode, (LPVOID)codestart, codesize); //複製被注入的程式碼到緩衝區
	DWORD dataoffset = codesize + sizeof(REMOTE_INFO) + 1;
	DWORD oldprotect, sztmp;
	//在目標程序中申請記憶體
	LPVOID lpcode = VirtualAllocEx(hprocess, NULL, CODE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	DWORD addrlocal = (DWORD)remotecode, addrremote = (DWORD)lpcode;
	//修改緩衝區記憶體屬性為可執行
	VirtualProtectEx(GetCurrentProcess(), remotecode, CODE_SIZE, PAGE_EXECUTE_READWRITE, &oldprotect);

	//修正被注入程式碼的API引數地址
	pri->ccall_LoadLibraryA = (DWORD)LoadLibraryA;
	pri->ccall_GetProcAddress = (DWORD)GetProcAddress;
	pri->ccall_VirtualFree = (DWORD)VirtualFree;
	pri->ccall_ExitThread = (DWORD)ExitThread;
	pri->ccall_MessageBoxA = (DWORD)MessageBoxA;
	pri->cdword_rpfun = (DWORD)lpcode;
	
	pri->csz_dllname = (char*)(addrremote + dataoffset);
	lstrcpyA((char*)(addrlocal + dataoffset), szdll);
	dataoffset += lstrlenA(szdll) + 1;
	
	pri->csz_InitModule = (char*)(addrremote + dataoffset);
	lstrcpyA((char*)(addrlocal + dataoffset), "InitModule");
	sztmp = addrlocal + dataoffset;
	dataoffset += lstrlenA((char*)(addrlocal + dataoffset)) + 1;
	
	pri->csz_msgtitle = (char*)(addrremote + dataoffset);
	lstrcpyA((char*)(addrlocal + dataoffset), "錯誤");
	dataoffset += lstrlenA((char*)(addrlocal + dataoffset)) + 1;
	
	pri->csz_msgerrorload = (char*)(addrremote + dataoffset);
	wsprintfA((char*)(addrlocal + dataoffset), "載入[%s]失敗", szdll);
	dataoffset += lstrlenA((char*)(addrlocal + dataoffset)) + 1;
	
	pri->csz_msgerrorinitmodule = (char*)(addrremote + dataoffset);
	wsprintfA((char*)(addrlocal + dataoffset), "獲取函式[%s]地址失敗", sztmp);
	dataoffset += lstrlenA((char*)(addrlocal + dataoffset)) + 1;
	
	WriteProcessMemory(hprocess, lpcode, remotecode, CODE_SIZE, &oldprotect);
	/*
	_asm
	{
		mov eax, lpcode;
		jmp eax;
	}
	*/
	CreateRemoteThread(hprocess, NULL, NULL, (LPTHREAD_START_ROUTINE)lpcode, (LPVOID)((DWORD)lpcode + codesize), NULL, NULL);
	return TRUE;
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
 	// TODO: Place code here.
	DWORD pid = 0;
	//測試時的目標(包含標題為"注入測試 - 記事本"的程式)
	HWND hwnd = FindWindow(NULL, _T("注入測試.txt - 記事本"));
	if(NULL == hwnd)
		return TRUE;
	GetWindowThreadProcessId(hwnd, &pid);
	//pid = GetCurrentProcessId();//首先在本程序內測試
	if(0 == pid)
		return TRUE;
	HANDLE hins = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, NULL, pid);
	if(NULL != hins)
	{
		char *szdll = "F:\\temp\\buildtmp\\testdll\\testdll.dll";
		AttachDllToProcessC(hins, szdll);
		CloseHandle(hins);
	}
	//while(TRUE)
	Sleep(5000);
	return 0;
}