VC++进程注入

概述:按照个人理解的来概述就是,将我们自己的一个dll注入到目标进程中去。这样目标进程就运行了我们的dll,在我们的dll中劫持目标函数的跳转指令----也就是目标进程在执行某一个函数时被我们拦截了,改成执行我们的函数。
详细:

本教程边写代码边解释,运行环境VS2012+Qt

源码链接http://download.csdn.net/download/sky_calls/10264654

第一步、创建一个目标进程TargetProcess

其实就是一个很简单的写串口操作
创建过程省略,代码如下

关键函数解释

void TargetProcess::writeCom()
{
HANDLE hCom; //串口句柄
hCom=CreateFile(L"COM1",//COM口
GENERIC_READ|GENERIC_WRITE, //允许读和写
0, //独占方式
NULL,
OPEN_EXISTING, //打开而不是创建
0, //同步方式
NULL);
if(hCom==(HANDLE)-1)
return;

SetupComm(hCom,1024,1024); //输出缓冲区的大小是1024
COMMTIMEOUTS TimeOuts; //设定读超时
TimeOuts.ReadIntervalTimeout=1000;
TimeOuts.ReadTotalTimeoutMultiplier=500;
TimeOuts.ReadTotalTimeoutConstant=5000; //设定写超时
TimeOuts.WriteTotalTimeoutMultiplier=500;
TimeOuts.WriteTotalTimeoutConstant=2000;
SetCommTimeouts(hCom,&TimeOuts); //设置超时
DCB dcb;
GetCommState(hCom,&dcb);
dcb.BaudRate=9600; //波特率为9600
dcb.ByteSize=8; //每个字节有8位
dcb.Parity='\0'; //无奇偶校验位
dcb.StopBits='\0'; //两个停止位
SetCommState(hCom,&dcb);
PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

//同步写串口
char lpOutBuffer[100];
QString tmpContent = "hello com1";
memcpy_s(lpOutBuffer, 100, tmpContent.toStdString().c_str(), tmpContent.length());
lpOutBuffer[tmpContent.length()] = 0;
DWORD dwBytesWrite=100;
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriteStat;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);

PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

CloseHandle(hCom);
}

第二步、创建要注入的dll工程 ApiHook

要注入的这个dll库必须有DllMain函数作为入口,否则dll里面的劫持操作无法完成
关键代码如下
typedef struct 
{
LPCSTR lpFunctionName; // name of api 要拦截的函数名字
LPCTSTR lpDllName; // name of dll that has the api要拦截函数所属dll
LPVOID lpRecallfn; // recall function address 自定义的替换函数
LPVOID lpApiAddr; // api address 原始函数地址
PBYTE pOrgfnMem; // memory to save first few bytes of api and execute jmp code 原始函数跳转指令
int nOrgfnMemSize; // size of pOrgfnMem 跳转指令的大小
} RECALL_API_INFO, *PRECALL_API_INFO;

// hook apis infomation
RECALL_API_INFO g_arHookAPIs[] = 
{
"CreateFileA", "Kernel32.dll", 
MyCreateFileA, CreateFileA,        NULL, 0,

"CreateFileW", "Kernel32.dll", 
MyCreateFileW, CreateFileW, NULL, 0,

"WriteFile", "Kernel32.dll", 
MyWriteFile, WriteFile, NULL, 0,

"WriteFileEx", "Kernel32.dll", 
MyWriteFileEx, WriteFileEx, NULL, 0
};
bool hookApi(PRECALL_API_INFO pApiRecall) // 参数为所劫持的函数信息

{
if (pApiRecall == NULL)
return false;
// 得到目标函数锁在的库名称
HMODULE hModule = LoadLibrary(pApiRecall->lpDllName);
if (!hModule)
return false;
// 得到目标函数在库里面的位置
FARPROC pfnStartAddr = (FARPROC)GetProcAddress(hModule, pApiRecall->lpFunctionName);
pApiRecall->lpApiAddr = pfnStartAddr; // 将目标函数保存起来,这一步可能不需要,没试下
if (!pfnStartAddr)
return false;


int nSize = 0; 
int nDisassemblerLen = 0;
while(nSize < 5) 

// GetOpCodeSize can get the assembly code size 得到跳转指令的大小 详见GetOpCodeSize的源文件解释
nDisassemblerLen = GetOpCodeSize((BYTE*)(pfnStartAddr) + nSize);
PrintMsg("nDisassemblerLen val %d\r\n", nDisassemblerLen);
nSize = nDisassemblerLen + nSize; 
}
PrintMsg("nSize val %d\r\n", nSize);


DWORD dwProtect = 0;
if (!VirtualProtect(pfnStartAddr, nSize, PAGE_EXECUTE_READWRITE, &dwProtect)) // 修改内存地址的属性,将原目标函数地址跳转指令改为可读写模式
return false;


// be sure that we must change pOrgfnMem's protect, because the code in pOrgfnMem 
// also need to execute 
pApiRecall->pOrgfnMem = new BYTE[5 + nSize]; // 这个内存区域将保存原内存的跳转指令
DWORD dwMemProtect = 0;


if (!VirtualProtect(pApiRecall->pOrgfnMem, 5 + nSize, PAGE_EXECUTE_READWRITE, &dwMemProtect))
{
delete [] pApiRecall->pOrgfnMem;
pApiRecall->pOrgfnMem = NULL;
return false;
}
pApiRecall->nOrgfnMemSize = 5 + nSize;


// 下面这几行就是将原函数的跳转指令储存在pOrgfnMem里面,因为在调用了自定义函数后还要调用原函数,以免影响目标进程的功能
memcpy(pApiRecall->pOrgfnMem, pfnStartAddr, nSize);
*(BYTE*)(pApiRecall->pOrgfnMem + nSize) = 0xE9;
*(DWORD*)(pApiRecall->pOrgfnMem + nSize + 1) = (DWORD)pfnStartAddr + nSize - (DWORD)(pApiRecall->pOrgfnMem + 5 + nSize);
*(BYTE*)(pfnStartAddr) = 0xE9;
*(DWORD*)((BYTE*)pfnStartAddr + 1) = (DWORD)pApiRecall->lpRecallfn - ((DWORD)pfnStartAddr + 5); // lpRecallfn,这是我们自定义的函数,这段语句的作业是用我们自定义的函数覆盖原函数,例如MyWriteFile将会覆盖WriteFile
memset((BYTE*)pfnStartAddr + 5, 0x90, nSize - 5);
// be sure that we must set the rest to 0x90(assembly code for nop, do nothing, 
// and occupy one byte), because we should't change the assembly code


VirtualProtect(pfnStartAddr, nSize, dwProtect, &dwProtect); // 将新函数的跳转指令的内存属性修改为原来的样子,可查看VirtualProtect的作用
return true;
}

第三步、创建注入工程 TestBqDll

执行进程注入操作

操作如下

// 提升进程的权限,不过好像不是必须的

bool promotePrivilege()
{
HANDLE  hToken;
LUID    sedebugnameValue;
TOKEN_PRIVILEGES tkp;
if  ( !OpenProcessToken(  GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)
)
{
return false;
}
if( !LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue) )
{
CloseHandle(hToken);
return false;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if( !AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL) )
{
CloseHandle(hToken);
return false;
}
return true;
}


// 根据进程的名称获得进程ID,因为进程注入需要进程的ID号
void GetTargetProcessIds(std::string inTarget, std::vector<int > &outIds)
{
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(hProcessSnap == INVALID_HANDLE_VALUE)
return;
BOOL bProcess = Process32First(hProcessSnap, &pe32);
int targetNameLen = inTarget.length();
while(bProcess)
{
int searchLen = wcslen(pe32.szExeFile);
if (targetNameLen == searchLen)
{
bool isEqualName = true;
for (int i = 0; i < targetNameLen; ++i)
{
if (inTarget[i] != pe32.szExeFile[i])
{
isEqualName = false;
break;
}
}
if (isEqualName)
outIds.push_back(pe32.th32ProcessID);
}


// 继续查找
bProcess = Process32Next(hProcessSnap,&pe32);
}
CloseHandle(hProcessSnap);
}


// 进程注入
bool InjectDllByProcessID(const std::wstring dllPath, unsigned long inProcessID)
{
wchar_t* DirPath = new wchar_t[MAX_PATH];
wchar_t* FullPath = new wchar_t[MAX_PATH];
GetCurrentDirectory(MAX_PATH, DirPath);
swprintf_s(FullPath, MAX_PATH, dllPath.c_str(), DirPath);


HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE, FALSE, inProcessID);
if (hProcess == NULL)
{
delete[] DirPath;
delete[] FullPath;
return false;
}


LPVOID LoadLibraryAddr = (LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"),
"LoadLibraryW");
if (LoadLibraryAddr == NULL)
{
CloseHandle(hProcess);
delete[] DirPath;
delete[] FullPath;
return false;
}


LPVOID LLParam = (LPVOID)VirtualAllocEx(hProcess, NULL, (wcslen(FullPath) + 1) * sizeof(wchar_t),
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, LLParam, FullPath, (wcslen(FullPath) + 1)* sizeof(wchar_t), NULL);


HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryAddr,
LLParam, NULL, NULL);


// 等待远程线程结束    
::WaitForSingleObject(hRemoteThread, INFINITE);    
// 清理    
::VirtualFreeEx(hProcess, LLParam, (wcslen(FullPath) + 1), MEM_DECOMMIT);    
::CloseHandle(hRemoteThread);    
::CloseHandle(hProcess);


delete[] DirPath;
delete[] FullPath;
return true;

}

void TestBqDll::inject()
{
promotePrivilege();
std::vector<int > processIds;
//GetTargetProcessIds("PosTouch.exe", processIds);
GetTargetProcessIds("TargetProcess.exe", processIds);
QString _workPath = QCoreApplication::applicationDirPath();
QString dllPath = _workPath + "/ApiHook.dll";
if (processIds.size() > 0)
InjectDllByProcessID(dllPath.toStdWString(), processIds[0]);

}


源码链接http://download.csdn.net/download/sky_calls/10264654

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
进程注入自己的dll 带有测试dll 路径和要注入的程序可以自己改 hRemoteProcess=OpenProcess(PROCESS_CREATE_THREAD| //允许远程创建线程 PROCESS_VM_OPERATION | //VM操作 PROCESS_VM_WRITE , //允许写 FALSE,dwProcessID); if(!hRemoteProcess) AfxMessageBox(L"无法打开目标进程"); // KillTimer(m_ntime); //计算DLL路径需要多大内存 int cb=(1+lstrlenW(pszLibFile))*sizeof(WCHAR); //使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名缓冲区 pszLibFileRemote=(PWSTR)VirtualAllocEx(hRemoteProcess,NULL,cb,MEM_COMMIT,PAGE_READWRITE); if(pszLibFileRemote==NULL) { AfxMessageBox(L"建立内存失败"); CloseHandle(hRemoteProcess); return; } //使用WriteProcessMemory函数将DLL的路径名复制到远程进程的内存空间 BOOL iReturnCode=WriteProcessMemory (hRemoteProcess,pszLibFileRemote,(PVOID)pszLibFile,cb,NULL); if(!iReturnCode) { AfxMessageBox(L"写入错误"); VirtualFreeEx(hRemoteProcess,NULL,0,MEM_RELEASE); CloseHandle(hRemoteThread); CloseHandle(hRemoteProcess); return; } //计算loadlibraryW入口地址 HMODULE hModule=LoadLibrary(L"C:\\WINDOWS\\system32\\kernel32"); PTHREAD_START_ROUTINE pfnStartAddr=( PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")),"LoadLibraryW"); hRemoteThread=CreateRemoteThread(hRemoteProcess,NULL,0,pfnStartAddr,pszLibFileRemote,0,NULL); if(hRemoteThread==NULL) { //等待线程结束 WaitForSingleObject(hRemoteThread,INFINITE); DWORD RetV; if(GetExitCodeThread(hRemoteThread,&RetV)) CloseHandle(hRemoteThread);

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值