我的方法:
通过CreateRemoteThread的方法注入麻烦,所以直接用hook,写线程钩子.
再将recv的地址前5个字节保存到old
再将recv地址前5字节改成jmp xxxxxx的机器码(xxxxxx为自己的函数newRecv)
再到自己newRecv把buf数据写a.txt文件中,再newRecv结尾将old还原到recv函数前5字节,并调用recv
上面是我的想法.不知能否实现?
但问题就是,最后recv函数还原了.也就是recv不会再跳到newRecv中去了.那下次有数据来就不会先执行newRecv再执行recv了那怎么办?
我可是想一直截取recv的数据哦..
通过CreateRemoteThread的方法注入麻烦,所以直接用hook,写线程钩子.
再将recv的地址前5个字节保存到old
再将recv地址前5字节改成jmp xxxxxx的机器码(xxxxxx为自己的函数newRecv)
再到自己newRecv把buf数据写a.txt文件中,再newRecv结尾将old还原到recv函数前5字节,并调用recv
上面是我的想法.不知能否实现?
但问题就是,最后recv函数还原了.也就是recv不会再跳到newRecv中去了.那下次有数据来就不会先执行newRecv再执行recv了那怎么办?
我可是想一直截取recv的数据哦..
解决方案 »
- 怎么限制CEdit只能输入小写字母
- 求个officeXP或VS.Net风格MDI源代码下载
- (How to expand the specified key of regedit ?)如何自动展开 Regedit 指定路径的键?
- 下面这段sql语句怎么这么多分号?怎么分?
- 如何改变按钮的位置?
- “手册“是什么东西??
- 哪个兄弟给个afxdtctl.h,我安装时少了这个。急用,希望斑竹不要删了[email protected]
- 怎么将字体大小磅转换为逻辑单位高度?谢谢
- 求解:如何使用GDI+画一个风扇的平面图?
- 这个问题连bill.gates都难解决?非技术
- 如何用VC++实现FTP服务器上文件与本地电脑上文件同步更新
- 关于AfxMessageBox的问题
应该反汇编recv的入口指令,取出不少于5字节的完整指令,将其搬移的自己的内存中,并在后面接上一条jmp指令,跳回原本的下一条指令。
你可以在网上搜一下,有更详细的说明和源代码。
同步问题,当你正在修改recv前5个字节,线程被切换出去了怎么办?况且函数头部5字节不一定是整数条指令(虽然xp sp2版本的recv是),所以这就存在了同步以及指令碎片问题.//前5字节不是整数条指令
ntdll!NtCreateFile:
7c92d682 b825000000 mov eax,25h
7c92d687 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c92d68c ff12 call dword ptr [edx]
7c92d68e c22c00 ret 2Ch用Microsoft出的Detours吧..或者改用IAT钩子。
LZ觉得CreateRemoteThread麻烦就给你一个类吧.
////////////////////////////////////////////////
// RemThreadInjector.h文件
#include <windows.h>class CRemThreadInjector
{
public:
CRemThreadInjector(LPCTSTR pszDllName);
~CRemThreadInjector(); // 注入DLL到指定的进程空间
BOOL InjectModuleInto(DWORD dwProcessId); // 从指定的进程空间卸载DLL
BOOL EjectModuleFrom(DWORD dwProcessId);protected:
char m_szDllName[MAX_PATH]; // 调整特权级别
static BOOL EnableDebugPrivilege(BOOL bEnable);
};////////////////////////////////////////////////
// RemThreadInjector.cpp文件
#include "stdafx.h"
#include "RemThreadInjector.h"
#include <tlhelp32.h>CRemThreadInjector::CRemThreadInjector(LPCTSTR pszDllName)
{
strncpy(m_szDllName, pszDllName, MAX_PATH);
EnableDebugPrivilege(TRUE);
}CRemThreadInjector::~CRemThreadInjector()
{
EnableDebugPrivilege(FALSE);
}BOOL CRemThreadInjector::EnableDebugPrivilege(BOOL bEnable)
{
// 附给本进程特权,以便访问系统进程
BOOL bOk = FALSE;
HANDLE hToken;
// 打开一个进程的访问令牌
if(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
// 取得特权名称为“SetDebugPrivilege”的LUID
LUID uID;
::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &uID); // 调整特权级别
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = uID;
tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
::AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
bOk = (::GetLastError() == ERROR_SUCCESS); // 关闭访问令牌句柄
::CloseHandle(hToken);
}
return bOk;
}BOOL CRemThreadInjector::InjectModuleInto(DWORD dwProcessId)
{
if(::GetCurrentProcessId() == dwProcessId)
return FALSE; // 首先查看目标进程是否加载了这个模块
BOOL bFound = FALSE;
MODULEENTRY32 me32 = { 0 };
HANDLE hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
me32.dwSize = sizeof(MODULEENTRY32);
if(::Module32First(hModuleSnap, &me32))
{
do
{
if(lstrcmpiA(me32.szExePath, m_szDllName) == 0)
{
bFound = TRUE;
break;
}
}
while(::Module32Next(hModuleSnap, &me32));
}
::CloseHandle(hModuleSnap); // 如果能够找到,就不重复加载了(因为重复加载没有用,Windows只将使用计数加1,其它什么也不做)
if(bFound)
return FALSE;
// 试图打开目标进程
HANDLE hProcess = ::OpenProcess(
PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION, FALSE, dwProcessId);
if(hProcess == NULL)
return FALSE;
// 在目标进程中申请空间,存放字符串pszDllName,作为远程线程的参数
int cbSize = (strlen(m_szDllName) + 1);
LPVOID lpRemoteDllName = ::VirtualAllocEx(hProcess, NULL, cbSize, MEM_COMMIT, PAGE_READWRITE);
::WriteProcessMemory(hProcess, lpRemoteDllName, m_szDllName, cbSize, NULL); // 取得LoadLibraryA函数的地址,我们将以它作为远程线程函数启动
HMODULE hModule=::GetModuleHandle("kernel32.dll");
LPTHREAD_START_ROUTINE pfnStartRoutine =
(LPTHREAD_START_ROUTINE)::GetProcAddress(hModule, "LoadLibraryA");
// 启动远程线程
HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, lpRemoteDllName, 0, NULL);
if(hRemoteThread == NULL)
{
::CloseHandle(hProcess);
return FALSE;
}
// 等待目标线程运行结束,即LoadLibraryA函数返回
::WaitForSingleObject(hRemoteThread, INFINITE);
::CloseHandle(hRemoteThread);
::CloseHandle(hProcess);
return TRUE;
}BOOL CRemThreadInjector::EjectModuleFrom(DWORD dwProcessId)
{
if(::GetCurrentProcessId() == dwProcessId)
return FALSE; // 首先查看目标进程是否加载了这个模块
BOOL bFound = FALSE;
MODULEENTRY32 me32 = { 0 };
HANDLE hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
me32.dwSize = sizeof(MODULEENTRY32);
if(::Module32First(hModuleSnap, &me32))
{
do
{
if(lstrcmpiA(me32.szExePath, m_szDllName) == 0)
{
bFound = TRUE;
break;
}
}
while(::Module32Next(hModuleSnap, &me32));
}
::CloseHandle(hModuleSnap); // 如果找不到就返回出错处理
if(!bFound)
return FALSE; // 试图打开目标进程
HANDLE hProcess = ::OpenProcess(
PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION, FALSE, dwProcessId);
if(hProcess == NULL)
return FALSE;
// 取得LoadLibraryA函数的地址,我们将以它作为远程线程函数启动
HMODULE hModule=::GetModuleHandle("kernel32.dll");
LPTHREAD_START_ROUTINE pfnStartRoutine =
(LPTHREAD_START_ROUTINE)::GetProcAddress(hModule, "FreeLibrary");
// 启动远程线程
HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, me32.hModule, 0, NULL);
if(hRemoteThread == NULL)
{
::CloseHandle(hProcess);
return FALSE;
}
// 等待目标线程运行结束,即FreeLibrary函数返回
::WaitForSingleObject(hRemoteThread, INFINITE);
::CloseHandle(hRemoteThread);
::CloseHandle(hProcess);
return TRUE;
}使用方法:
CRemThreadInjector m_injector(dll的路径);
m_injector.InjectModuleInto(要注入的进程ID);
#include "replace.h"#pragma data_seg("publicdata")
HHOOK hhook=NULL;
HINSTANCE hInstance=NULL;
#pragma data_seg()BYTE oldData[5];
BYTE newData[5];
HANDLE hProc;
FARPROC recvAdd;BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
hInstance = GetModuleHandle(NULL);
break;
}
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
{
UnHook();
}
}
return TRUE;
}void WINAPI InstallHook(DWORD threadId)
{
hhook = SetWindowsHookEx(WH_GETMESSAGE, HookProc, hInstance, threadId);
Record();
SetHookStart();
}void WINAPI UnHook()
{
UnhookWindowsHookEx(hhook);
}LRESULT CALLBACK HookProc(int code, WPARAM wparam, LPARAM lparam)
{
return CallNextHookEx(hhook, code, wparam, lparam);
}void WINAPI Record()
{ newData[0] = 0xe9;
hProc = ::GetCurrentProcess();
recvAdd = GetProcAddress(LoadLibrary("ws2_32.dll"), "recv");
memcpy(oldData, (char *)recvAdd, 5);
DWORD *p = (DWORD*)&newData[1];
*p = (DWORD *)recvAll-(DWORD *)recvAdd-5;
}void WINAPI SetHookStart()
{
::WriteProcessMemory(hProc, recvAdd, newData, 5, NULL);
}void WINAPI SetHookEnd()
{
::WriteProcessMemory(hProc, recvAdd, oldData, 5, NULL);
}int WINAPI recvAll(SOCKET s, char *str, int len, int flag)
{
fstream file;
file.open("C:\\recv.txt", ios::app|ios::out|ios::in);
file.write(str, strlen(str));
file.close();
SetHookEnd();
recv(s, str, len, flag);
SetHookStart();
return 0;
}
我提一种新的方法,你可以试试。
在注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows下面,修改AppInit_DLLs值,给出一个dll的名称及路径,所有程序启动时会自动加载该dll。顺便提两点你的代码中与SetWindowsHook有关的问题:
GetModuleHandle(NULL)返回的是exe的句柄,你需要的是dll的句柄,直接用DllMain的第1个参数即可。
SetWindowsHookEx的最后参数给0才能Hook所有线程。
#include "stdafx.h"
#include "replace.h"HHOOK hhook=NULL;
HINSTANCE hInstance=NULL;BYTE oldData[5];
BYTE newData[5];
HANDLE hProc;
FARPROC recvAdd;
HANDLE hDebug;
DWORD pid;BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
//hInstance = GetModuleHandle(NULL);
hInstance = (HINSTANCE)hModule;
break;
}
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
{
UnHook();
}
}
return TRUE;
}void WINAPI InstallHook(DWORD threadId)
{
hhook = SetWindowsHookEx(WH_CALLWNDPROC, HookProc, hInstance, threadId);
hDebug = ::CreateFile( "C:\\Trace.log", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 );
Record();
SetHookStart();
}void WINAPI UnHook()
{
UnhookWindowsHookEx(hhook);
}LRESULT CALLBACK HookProc(int code, WPARAM wparam, LPARAM lparam)
{
return CallNextHookEx(hhook, code, wparam, lparam);
}void WINAPI Record()
{
newData[0] = 0xe9;
hProc = ::GetCurrentProcess();
pid = ::GetCurrentProcessId();
OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
recvAdd = GetProcAddress(LoadLibrary("WS2_32.dll"), "WSARecv");
memcpy(oldData, (char *)recvAdd, 5);
DWORD *p = (DWORD*)&newData[1];
*p = (DWORD *)recvAll-(DWORD *)recvAdd-5;
}void WINAPI SetHookStart()
{
::WriteProcessMemory(hProc, recvAdd, newData, 5, NULL);
}void WINAPI SetHookEnd()
{
::WriteProcessMemory(hProc, recvAdd, oldData, 5, NULL);
}int WINAPI recvAll(SOCKET s, char *str, int len, int flag)
{
MessageBox(NULL, str, "内容", MB_OK);
DWORD dwSize;
::WriteFile( hDebug, str, strlen( str ), &dwSize, 0 ); SetHookEnd();
recv(s, str, len, flag);
SetHookStart();
return 0;
}存在问题就是不执行recvAll.也就是没执行自己的函数.但改成jmp好像成功了..
始终找不出问题.真郁闷. 因为是dll.所以也不能单步调.
谁有这样的经验的请指教.
#include "winsock2.h"
#include "stdio.h"
#pragma comment(lib,"ws2_32.lib")typedef unsigned int SOCKET;
REPLACE_API void WINAPI InstallHook(DWORD);
REPLACE_API void WINAPI UnHook();
LRESULT CALLBACK HookProc(int, WPARAM, LPARAM);
int WINAPI recvAll(SOCKET, char *, int, int);
void WINAPI Record();
void WINAPI SetHookStart();
void WINAPI SetHookEnd();我把.h也贴上来吧.大家好方便测试
SetWindowsHookEx的Hook所有线程是相对而言的,前提是同一桌面,言外之意就是那些不同桌面的线程Hook不到。MSDN中SetWindowsHookEx的说明部分有明确指出。
#include "stdafx.h"
#include "replace.h"
// 以下大部分数据须定义在共享数据段
HHOOK hhook=NULL;
HINSTANCE hInstance=NULL;BYTE oldData[5];
BYTE newData[5];
HANDLE hProc;
FARPROC recvAdd;
HANDLE hDebug;
DWORD pid;BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
//hInstance = GetModuleHandle(NULL);
hInstance = (HINSTANCE)hModule; // 注意,每个进程都会执行
break;
}
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
{
UnHook(); // 每个进程都会执行,不能这样UnHook
}
}
return TRUE;
}
// 导出函数需要加__declspec(dllimport)
void WINAPI InstallHook(DWORD threadId) // Hook全局要传0进来
{
hhook = SetWindowsHookEx(WH_CALLWNDPROC, HookProc, hInstance, threadId);
hDebug = ::CreateFile( "C:\\Trace.log", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 );
Record();
SetHookStart(); // 要先调试验证此时各进程都已LoadLibrary
// 要调试验证修改的recv函数入口代码是否对所有进程有效
}void WINAPI UnHook()
{
UnhookWindowsHookEx(hhook);
}LRESULT CALLBACK HookProc(int code, WPARAM wparam, LPARAM lparam)
{
return CallNextHookEx(hhook, code, wparam, lparam);
}void WINAPI Record()
{
newData[0] = 0xe9;
hProc = ::GetCurrentProcess(); // 记得关句柄
pid = ::GetCurrentProcessId();
OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); // 不要返回值还执行它干嘛?
recvAdd = GetProcAddress(LoadLibrary("WS2_32.dll"), "WSARecv");
memcpy(oldData, (char *)recvAdd, 5);
DWORD *p = (DWORD*)&newData[1];
*p = (DWORD *)recvAll-(DWORD *)recvAdd-5; // DWORD 改成 BYTE
}void WINAPI SetHookStart()
{
::WriteProcessMemory(hProc, recvAdd, newData, 5, NULL); // 内存保护,代码段默认只读
}void WINAPI SetHookEnd()
{
::WriteProcessMemory(hProc, recvAdd, oldData, 5, NULL);
}int WINAPI recvAll(SOCKET s, char *str, int len, int flag)
{
MessageBox(NULL, str, "内容", MB_OK); // 服务进程无法弹出
DWORD dwSize;
::WriteFile( hDebug, str, strlen( str ), &dwSize, 0 ); // 除非本进程,否则hDebug不能用 SetHookEnd(); // 从End到Start过程必须同步完成
recv(s, str, len, flag);
SetHookStart();
return 0; // 每次接收数据都是0!
}
// 整个程序都没有异常判断处理,很容易死机
某游戏进程.所以你提出的问题
::WriteProcessMemory(hProc, recvAdd, newData, 5, NULL); // 内存保护,代码段默认只读这个问题才是问题.呵呵.太谢谢你了.等我测一下.如果成功了.我马上结贴给你加分.
void WINAPI SetHookStart()
{
DWORD dwOld;
::VirtualProtect(recvAdd, 5, PAGE_READWRITE, &dwOld);
::WriteProcessMemory(hProc, recvAdd, newData, 5, NULL);
::VirtualProtect(recvAdd, 5, PAGE_READONLY, &dwOld);
}void WINAPI SetHookEnd()
{
DWORD dwOld;
::VirtualProtect(recvAdd, 5, PAGE_READWRITE, &dwOld);
::WriteProcessMemory(hProc, recvAdd, oldData, 5, NULL);
::VirtualProtect(recvAdd, 5, PAGE_READONLY, &dwOld);
}
这样还是不行
还有<windows核心编程应用程序捆定>书上.例子全是直接WriteProcMemory()之前并没virtualProtect修改权限,况且我修改了还是不行.
SetHookStart();不能紧跟着SetWindowsHookEx()后面.
因为当挂钩没挂住时,dll还没有映射到被挂进程的空间里.
问题2, 参数问题..
recv函数与WSARecv参数是完全不同的..而我将WSARect前5字节改成转跳recv参数的函数,当然有问题
Record();
SetHookStart(); // 要先调试验证此时各进程都已LoadLibrary问题1我已经给你指出来了。
问题2是没想到你会写不同的函数,所以没注意看。顺便再提一下,上面这3行代码应该加到DllMain或者HookProc里面并判断只在目标进程执行一次。
另外,你的程序中应该还存在其它问题,等你遇到问题的时候可以参考我前面标出的那些注释。
Recv : ws_32.dll 导出地址
MyRecv:新的Recv函数
CodeBuff:代码中转(别名OrgionRecv)将 Recv的前段指令(使用指令测长代码)大于5字节[长度:codelen],复制到CodeBuff,CodeBuff未层加到Jmp Recv+codelen;
将Recv的首指令改成Jmp MyRecv.MyRecv(...)
{
puts(buff);
return OrgionRecv(...);
}这样就不知道切换了,另外切换在多线程中是不安全的
//--------------------
问题在于你的HOOK方法,使用以下方法就不会存在你的问题
Recv : ws_32.dll 导出地址
MyRecv:新的Recv函数
CodeBuff:代码中转(别名OrgionRecv) 将 Recv的前段指令(使用指令测长代码)大于5字节[长度:codelen],复制到CodeBuff,CodeBuff未尾加到Jmp Recv+codelen;
将Recv的首指令改成Jmp MyRecv. MyRecv(...)
{
int ret=OrgionRecv(...);
puts(buff);
return ret;
} 这样就不需要切换了,另外切换在多线程中是不安全的