自己修改 WS2_32 中的send函数, (通过浩方平台联网)
具体方法是 修改前 5个字节跳到 自己的Mysend中。 用互斥来防止多线程出现的问题。 可以说里面什么都没做。
但只要已进入别人的房间,就崩溃。。
// 互斥信号量
HANDLE hMutex = NULL;
typedef int(*PFunSend)( SOCKET, const char FAR *, int , int); // send 函数指针
PFunSend pSend;int MySend( SOCKET s, const char FAR *buf, int len, int flags )
{
// 进入缓冲区
WaitForSingleObject( hMutex, INFINITE ); // 改回源地址地址
int nTmp = 0;
for(nTmp = 0; nTmp < nSize; nTmp ++)
pFuncAddr[nTmp] = uszBuf[nTmp]; // 调用原函数
pSend = (PFunSend)pFuncAddr;
nTmp = pSend(s, buf, len, flags ); // 改成本地地址
pFuncAddr[0] = 0xE9;
*(PDWORD)&pFuncAddr[1] = dwSrcOffset; ReleaseMutex(hMutex); return nTmp;
}我也很想自己解决这个问题, 但是 自己调试了好长时间, 而且自己写的多线程调用 + 更改IAT表的测试例子 一点问题都没有。故在此求救
具体方法是 修改前 5个字节跳到 自己的Mysend中。 用互斥来防止多线程出现的问题。 可以说里面什么都没做。
但只要已进入别人的房间,就崩溃。。
// 互斥信号量
HANDLE hMutex = NULL;
typedef int(*PFunSend)( SOCKET, const char FAR *, int , int); // send 函数指针
PFunSend pSend;int MySend( SOCKET s, const char FAR *buf, int len, int flags )
{
// 进入缓冲区
WaitForSingleObject( hMutex, INFINITE ); // 改回源地址地址
int nTmp = 0;
for(nTmp = 0; nTmp < nSize; nTmp ++)
pFuncAddr[nTmp] = uszBuf[nTmp]; // 调用原函数
pSend = (PFunSend)pFuncAddr;
nTmp = pSend(s, buf, len, flags ); // 改成本地地址
pFuncAddr[0] = 0xE9;
*(PDWORD)&pFuncAddr[1] = dwSrcOffset; ReleaseMutex(hMutex); return nTmp;
}我也很想自己解决这个问题, 但是 自己调试了好长时间, 而且自己写的多线程调用 + 更改IAT表的测试例子 一点问题都没有。故在此求救
之前就是这种方法, 在xp虚拟机下测试得好好的, 10个线程 调用 都没问题,回到win7下, 内存不可写。。
今天请教了一下, 貌似win权限更强了, 好像是不允许EIP指向数据区, 得给数组加权限
但是还面临一个问题。。 由于要占用5个字节, 难免会把 系统库中的 send函数 中某条执行给破坏掉,,而且E9 很有可能跟其他数据 结合成为其它指令,, 所以 今晚上回去时得好好调试一下
send的前五字节包含完整的指令,因此可以先把原来的指令备份,如果要调用原来的函数,先执行备份的,再跳回去e9只会和后面4字节结合,保证后面四字节是正确的偏移量即可
// 全局变量
unsigned char uszBufStore_Send[20] = {0};
int nByteSize_Send = 5;
unsigned char* pFuncAddr_Send = NULL;
typedef int (*PFunSend)(SOCKET, const char FAR *, int , int);
PFunSend pSend;// 修改IAT表后的函数
int WINAPI MySend( SOCKET s, const char FAR *buf, int len, int flags )
{
*(char*)(buf + 36) = 0x45; // TODO: 已经删除掉了互斥改回源send的代码 // 调用原函数
return pSend(s, buf, len, flags );
}
dll开始的时候要执行下面程序: 对无关紧要的做出了删改 FARPROC fp = GetProcAddress(hLibrary, "send");
pFuncAddr_Send = (unsigned char *)fp;
// 复制一份副本到数组
for (int i = 0; i < nByteSize_Send; i ++)
uszBufStore_Send[i] = pFuncAddr_Send[i]; DWORD dwSrcAddr = (DWORD)(pFuncAddr_Send + 5); // 源地址要加上五个字节
DWORD dwDesAddr = (DWORD)MySend;
dwSrcOffset = dwDesAddr - dwSrcAddr; // 获取原来进程的属性
hProcess = ::GetCurrentProcess(); if (VirtualProtectEx(hProcess, (LPVOID)pFuncAddr_Send, nByteSize_Send + 2, PAGE_EXECUTE_READWRITE, &dwOldProtectCodeSeg))
{
fprintf(pFile, "代码段可写\r\n");
pFuncAddr_Send[0] = 0xE9;
*(PDWORD)&pFuncAddr_Send[1] = dwSrcOffset; if (!VirtualProtectEx(hProcess, (LPVOID)uszBufStore_Send, 20, PAGE_EXECUTE_READWRITE, &dwOldProtectDataSeg))
{
fprintf(pFile, "数据段不可执行可写 关闭程序, 改回原属性\r\n");
EndCokeHouse(hModule); // 关闭
return;
}
else
{
fprintf(pFile, "数据段属性修改完毕,进行增加跳转到代码段代码\r\n");
DWORD dwDataSegmentAddr = (DWORD)(uszBufStore_Send + nByteSize_Send + 6);
DWORD dwDataSegmentOffset = dwSrcAddr - dwDataSegmentAddr; uszBufStore_Send[nByteSize_Send] = 0x90; // 空操作
uszBufStore_Send[nByteSize_Send + 1] = 0xe9;
*(PDWORD)&uszBufStore_Send[nByteSize_Send + 2] = dwDataSegmentOffset; pSend = (PFunSend)(void*)uszBufStore_Send;
}
原始sendMySend中
数据段数组中
typedef int (__stdcall *PFunSend)(SOCKET, const char FAR *, int , int);而且想要在data段里执行代码时,也应该先修改下data段的属性为可执行吧。
VirtualProtect ( (hProcess, (LPVOID)uszBufStore_Send, nByteSize_Send + 2, PAGE_EXECUTE_READWRITE, &dwOldProtectCodeSeg));//就好希望有帮助
而且我已经排列组合试过 加过各种 WINAPI了, 考虑到堆栈平衡,又都给去掉了。。
堆栈平衡,真是很难搞啊。。
send api 应该是 __stdcall 自动清栈, 那么send后面一定有清栈的代码
MySend 应该是 __stdcall 自动清栈,, 但是
数组中 的调用也要自动清栈吗》? 数组中可是要跳回 send中去得。。 那么 就可以直接运行send的清栈代码了不对吗?
恐怕我得hook send后面几个字节了。 初步的想法,,,难度还真超过自己想象啊, 堆栈平衡一道大坎 要越过
是啊, 我在纸上一个一个push 一个一个pop, 的记录, 发现也是对的啊。 所以我开始怀疑我自己。于是 精神崩溃
但是也不能啊,我在一开始写的代码
互斥
改回send的地址
调用send
改成MySend的地址
互斥结束这个流程不会错啊,, 真的不知道浩方到底有没有改什么东东,,,
IAT hook不更好 /;^]
我还以为我的这种方法 就是 修改IAT呢?? 难道不是吗??谢谢楼上哈, 这几天辛苦你了。。
哦,这样啊, 看来我得去查查啥叫 IAT hook, 我还以为我的方法就是呢。。
我在外面有个先给你分的帖子, 你去恢复一下把
hook之后的send
MySend中
数组中
这是程序很可能正在执行你替换那5个字节 此时被换掉 可能会使程序崩溃
尽量能让程序在联网直接完成hook操作
IAT HOOK是在内存中,自己解析PE头,然后通过PE头获得要HOOK的目标模块IAT表的里对应API指针的位置,接着在要HOOK的目标DLL的EAT表的位置,修改EAT表里API指针的值。不过你的问题是出在
call [pSend]
add esp, 0x10
retn 0x10这个ws2_32.dll里的send,它自己的返回就是
retn 0x10
不是默认的__cdecl调用类型的,即不用你手动
add esp, 0x10 平衡堆栈。
定义pSend这个函数指针的类型为__stdcall就好 /:^}
话说你们谁去 上海高速rpg砖房 建立一个 挂机地图去。?
当我的inline hook 上去后 直接 返回 int 3 了, 能不崩溃吗。
hook 后面5个字节固然是可以的, 但是这样做未必会达到我的目的, 因为 浩方已经在 前5个字节把数据包发出去了,, 我后面再更改也没用了。
你说的不失为一种方法, 但是我想尝试 hook send的 父调用试试, 看看父调用中有没有发送的包数据。。
有点不太明白你的意思你指的是 hook 5到10 的字节吗?
我觉得 在浩方上 send函数的作用只是 给 浩方自己的函数传递参数而已 而 hook 浩方自己的函数我无从下手。。 所以就考虑 hook 上一级函数。。
整理了一下思路, 发现是这样的流程:
1. 浩方启动war3 (send值正常)
2. 我注入的dll更改 send 到达 Mysend( jmp到我的mysend)
3. 进入房间, 调用send
4. 浩方改掉 send , 改成它的 内容
5. 跳转到int 3, 退出。。
呵呵, IAT 不会啊, 正在看 PE文件结构。我觉得我应该下载一个钩子库试一下, 不过我还是觉得一开始底层一点 好处多多。。你经验很丰富啊。。 经常做这个吗?