首页
社区
课程
招聘
[原创][Hook][ws2_32.dll]
发表于: 2019-1-31 20:38 15987

[原创][Hook][ws2_32.dll]

2019-1-31 20:38
15987

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?

2.代码的编写流程是如何?

ps:
1.跳转指令的位置不一定必须在开始,也可以在别处.
2.跳转指令不一定要使用jmp,其他和jmp等价的指令(sub,push等)都可.
3.跳转完毕后要恢复opcode否则会无限递归.

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为原点而扩展的脑图里的所有知识点还是有点意思的.
(///^_^....... 哈?)

 
 
 
#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;
}
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);
}
  • Recv_Server

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-2-20 15:09 被Weaving编辑 ,原因:
收藏
免费 6
支持
分享
最新回复 (11)
雪    币: 21
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
下载源码来研究。多谢
2019-2-1 11:58
0
雪    币: 12348
活跃值: (5113)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3

学习了,多谢楼主分享
2019-2-1 13:10
0
雪    币: 351
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
谢谢分享
2019-2-1 14:17
0
雪    币: 1392
活跃值: (5177)
能力值: ( LV13,RANK:240 )
在线值:
发帖
回帖
粉丝
5
单线程是没问题 ,对于多线程 这些函数调用非常频繁,执行HOOK,以及恢复的时候,利用memcpy修改的是5个字节,可能别的线程此时刚好调用recv,memcpy尚未完成,导致指令错误崩溃。 有很多方式解决 一种是利用 Interlock系列函数修改8字节,这样可能会导致错过一些调用。可以在另外的地方申请内存写入调用头,采取二次跳转,参考detours,还可以IAT EAT HOOK解决!!
最后于 2019-2-1 14:48 被IamHuskar编辑 ,原因:
2019-2-1 14:47
0
雪    币: 2157
活跃值: (12639)
能力值: ( LV12,RANK:312 )
在线值:
发帖
回帖
粉丝
6
http://blog.51cto.com/13352079/2347228
2019-2-1 16:51
0
雪    币: 300
活跃值: (2477)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
mark
2019-2-2 14:13
0
雪    币: 1535
活跃值: (695)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
mark
2019-2-3 09:41
0
雪    币: 11
活跃值: (165)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
mark
2019-5-27 13:27
0
雪    币: 86
活跃值: (1183)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
源码没得下载了?
2020-2-17 22:14
0
雪    币: 53
活跃值: (528)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
煞有介事的瞎搞。
2020-2-29 22:01
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
下载不了??
2020-4-4 20:26
0
游客
登录 | 注册 方可回帖
返回
//