目标程序:ws2_32.dll.
工具:
1.Visual Studio
2.DebugView
知识储备
1.dll的编写和加载流程.
2.Windows核心编程.
3.维基百科:Hooking.
4.Socket网络编程.
目标:
编写dll文件Hook调用ws2_32.dll的Send和Recv函数的程序,截取程序收发的数据包.
PS:当逆向程序时发现有反调试或是加壳,而你又暂时只需要程序的网络模块的收发数据时,Hook程序调用的网络函数是个不错选择.
思路
1.什么是API的Hook,原理和本质是什么,最后如何Hook?
答
- 实例:消息钩子算是Hook的一个实例.
- 原理:对函数内部进行挂钩处理,获取参数甚至修改执行流程跳转到自定义的函数中去执行.
- 本质:修改EIP指向的下一条指令,达到修改正常运行逻辑的目的.
- 操作:在目标函数内部修改字节,写入跳转地址的指令,防止程序崩溃需要在自定义函数中修复原先修改的内容后正常返回.
2.代码的编写流程是如何?
答
- Socket编程:编写两个示例分别调用Send/Recv函数进行通信.
- DLL编程:编写DLL文件获取Send/Recv的函数地址,进行挂钩截获数据.
- 注入利用:DLL的注入技术种类繁多,最为方便快捷有两种,远线程注入和注册表注入.
步骤
一、Socket编程
#include "stdafx.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
VOID eMsg(char* msg);
int _tmain(int argc, _TCHAR* argv[])
{
//HINSTANCE hlib = LoadLibrary(L"afflux.dll");
//if (!hlib)
// error_msg("error:000:loadlibrary_error\n");
//init wsadata
WSADATA wsd;
int code;
code = WSAStartup(MAKEWORD(2, 2), &wsd);
if (code == SOCKET_ERROR)
eMsg("error:001:init_error\n");
if (HIBYTE(wsd.wVersion) != 2 || LOBYTE(wsd.wVersion) != 2)
eMsg("error:002:version_error\n");
//create socket
SOCKET sSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sSocket == SOCKET_ERROR)
eMsg("error:003:create_socket_error\n");
//bind
sockaddr_in Saddr;
Saddr.sin_port = htons(0x1234);
Saddr.sin_family = AF_INET;
Saddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
code = bind(sSocket, (sockaddr*)&Saddr, sizeof(sockaddr));
if (code == SOCKET_ERROR)
eMsg("error:004:bind_socket_error\n");
code = listen(sSocket, SOMAXCONN);
if (code == SOCKET_ERROR)
eMsg("error:005:listen_socket_error\n");
printf("server>>\n");
while (true)
{
SOCKET Csocket;
sockaddr_in Caddr;
int CaddrSize = sizeof(Caddr);
Csocket = accept(sSocket, (sockaddr*)&Caddr, &CaddrSize);
if (Csocket == INVALID_SOCKET)
eMsg("error:006:accept_client_error\n");
char buff[100] = "";
code = recv(Csocket, buff, 100, 0);
if (code == SOCKET_ERROR)
eMsg("error:005:recv_server_error\n");
printf("recv>>%s\n", buff);
}
return 0;
}
#include "stdafx.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
VOID eMsg(char* msg);
int _tmain(int argc, _TCHAR* argv[])
{
//HINSTANCE hlib = LoadLibrary(L"afflux.dll");
//if (!hlib)
// error_msg("error:000:loadlibrary_error\n");
//init wsadata
WSADATA wsd;
int code;
code = WSAStartup(MAKEWORD(2, 2), &wsd);
if (code == SOCKET_ERROR)
eMsg("error:001:init_error\n");
if (HIBYTE(wsd.wVersion) != 2 || LOBYTE(wsd.wVersion) != 2)
eMsg("error:002:version_error\n");
printf("Client>>\n");
while (true)
{
//create socket
SOCKET Csocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (Csocket == INVALID_SOCKET)
eMsg("error:003:create_socket_error\n");
//link
sockaddr_in Saddr;
Saddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
Saddr.sin_family = AF_INET;
Saddr.sin_port = htons(0x1234);
int SaddrSize = sizeof(Saddr);
code = connect(Csocket, (sockaddr*)&Saddr, SaddrSize);
if (Csocket == INVALID_SOCKET)
eMsg("error:004:link_server_error\n");
char buff[100] = "";
printf("input>>");
gets_s(buff, 50);
code = send(Csocket, buff, 50, 0);
if (code == SOCKET_ERROR)
eMsg("error:006:send_data_error\n");
closesocket(Csocket);
}
return 0;
}
二、Hook_Dll编写
1. LoadLibrary()
2. GetProcAddress()
fun* p = (fun*)GetProcAddress(GetModuleHandle(L"moduleName"), "functionName");
>>recv
int WSAAPI recv(
_In_ SOCKET s,
__out_data_source(NETWORK) char FAR * buf,
_In_ int len,
_In_ int flags);
-->
typedef int (WINAPI *pRecv)(UINT, PSTR, int, int);
>>send
int WSAAPI send(
_In_ SOCKET s,
_In_reads_bytes_(len) const char FAR * buf,
_In_ int len,
_In_ int flags
);
-->
typedef int (WINAPI *pSend)(UINT, PSTR, int, int);
jmp addr ==> E9 XX XX XX XX
1.win32程序地址占四个字节.
2.jmp和E9对应占一字节.
3.程序内存空间虽然分页管理但是地址还是连续的,即函数之间的位移可以计算.
地址A:Recv函数的开始地址
地址A+5:jmp addr(跳转指令)
地址B:MyRecv函数的开始地址
addr = B-(A+5)
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <windows.h>
#include <stdio.h>
#define SIZE 6
BYTE oldBytes[SIZE] = { 0 };
BYTE JMP[SIZE] = { 0 };
DWORD oldProtect, myProtect = PAGE_EXECUTE_READWRITE;
typedef int (WINAPI *pRecv)(UINT, PSTR, int, int);
pRecv pOrigAddress = NULL;
void BeginRedirect(LPVOID);
int WINAPI MyRecv(UINT s, PSTR buf, int len, int flags);
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
pOrigAddress = (pRecv)GetProcAddress(GetModuleHandle(L"WS2_32.dll"), "recv");
if (pOrigAddress != NULL)
BeginRedirect(MyRecv);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
int WINAPI MyRecv(UINT s, PSTR buf, int len, int flags)
{
VirtualProtect((LPVOID)pOrigAddress, SIZE, myProtect, &oldProtect);
memcpy(pOrigAddress, oldBytes, SIZE);
int retValue = recv(s, buf, len, flags);
memcpy(pOrigAddress, JMP, SIZE);
VirtualProtect((LPVOID)pOrigAddress, SIZE, oldProtect, &myProtect);
OutputDebugStringA("do Something!!");
printf("MyRecv>>%s\n",buf);
return retValue;
}
void BeginRedirect(LPVOID newFunction)
{
BYTE tempJMP[SIZE] = { 0xE9, 0x90, 0x90, 0x90, 0x90, 0xC3 };
memcpy(JMP, tempJMP, SIZE);
DWORD JMPSize = ((DWORD)newFunction - (DWORD)pOrigAddress - 5);
VirtualProtect((LPVOID)pOrigAddress, SIZE, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(oldBytes, pOrigAddress, SIZE);
memcpy(&JMP[1], &JMPSize, 4);
memcpy(pOrigAddress, JMP, SIZE);
VirtualProtect((LPVOID)pOrigAddress, SIZE, oldProtect, &myProtect);
}
ps:
1.跳转指令的位置不一定必须在开始,也可以在别处.
2.跳转指令不一定要使用jmp,其他和jmp等价的指令(sub,push等)都可.
3.跳转完毕后要恢复opcode否则会无限递归.
三、Dll的注入利用
1.DLL注入即让程序主动调用.dll文件在DLL PROCESS_ATTACH时时就会进行HOOK操作.
2.项目源码:https://github.com/muxurousec/Hook_ws2_32.dll
四、总结
对于Hook的使用环境和方式还是可以有很多变化的.
环境
1.函数:是函数都可以HOOK?
1.1 C++类的虚函数.
1.2 程序自定义的函数.
1.3 回调函数:线程回调、消息回调等.
1.4 用户层的其他DLL文件里面的函数.
1.5 内核层的SSDT/ShadowSSDT的函数.
......
2.保护:反Hook的保护?
2.1 程序自身的保护.
2.2 应用层的保护.
2.3 内核层的保护.
......
3.平台:不同操作系统或硬件平台的Hook?
3.1 windows.
3.2 linux.
3.3 Unix.
3.4 Mips.
3.5 Mac.
3.6 Ios.
3.7 Android.
4.语言:不同语言编写的函数Hook?
4.1 编译型:C/C++/Java/C#.
4.2 解释型:Python/PHP/Js.
......
形式
1.脱离DLL文操作,以二进制形式进行挂钩.
2.静态挂钩,来源修改或替换(IAT挂钩,DLL劫持).
3.框架:frida/Xposed/detours.
......
Hook的使用可以从windows系统的应用层到内核层进行纵向拓展,再从windows到linux(android)等其他不同系统或是平台进行横向对比,中途还会碰到程序或是系统的保护和崩溃,时不时的还可以去了解下流行的Hook框架原理,不得不说想要完全理解以Hook为原点而扩展的脑图里的所有知识点还是有点意思的.
(///^_^....... 哈?)
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
最后于 2020-2-20 15:09
被Weaving编辑
,原因: