远程线程+hook=监控?

见字如面,我是东北码农。

今天文章的关键字是“远程线程”,会带大家使用远程线程+inlinehook实现一个简陋的监控系统,偷偷记录用户执行了哪些程序,可能就像你单位的监控系统一样。

关注微信“东北码农”,回复remotethread可获取代码地址。

下面是效果图,可以记录执行哪些程序、函数参数、执行时间。你也会发现一些有趣的事,例如有时仅仅打开一个目录,就会触发git的缓存进程。

 

1、双击启动程序时发生了什么?

实现功能前,我们需要了解当我们双击执行一个程序时,到底发生了什么?

1.1、桌面程序-explorer.exe

例如启动一个浏览器,第一步需要先在桌面找到浏览器的图标。在windows系统中,桌面进程是explorer.exe,有点类似linux的shell。如果你现在打开任务管理器,就可以发现explorer.exe进程,如果结束掉explorer.exe进程,桌面就会马上会消失。

1.2、双击执行时发生了什么?

当双击浏览器图标时,就会启动浏览器进程。桌面程序explorer.exe会调用CreateProcess接口,把各项参数填好去创建一个进程。CreateProcess有很多参数,我们监控时只需要关心前两个参数就好,程序执行路径和程序函数。

1.3、如何实现监控?

我们需要在explorer.exe进程空间内hook CreateProcess。就像发射炮弹一样,hook CreateProcess我们可以写到一个dll中,作为炮弹。现在的问题是如何让这枚炮弹发射到explorer.exe进程中。这里进入本文正题:远程线程dll注入。

2、远程线程注入实现

本章节会介绍如何实现一个通用的远程线程注入的小工具,并使用这个工具注入我们的dll到explorer.exe中。

相信对Windows底层编程和系统安全熟悉的人并不陌生,远程线程实现时需要借助于一个Windows API函数CreateRemoteThread,通过它可以在另外一个进程中注入一个线程并执行。

实现函数很简单,仅仅20行代码(没有做返回值判断,仅为了展示记录)代码如下:

static bool remotethread_inject(DWORD pid,const char* dll_path) {
  HANDLE pro = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
  
  // step1:在目标进程申请内存  
  int dll_path_len = strlen(dll_path )+1;
  void* remote_buf = VirtualAllocEx(pro, NULL, dll_path_len, MEM_COMMIT, PAGE_READWRITE);  
  // step2:在目标进程写入dll路径
  BOOL ret = WriteProcessMemory(pro, remote_buf, (LPVOID)dll_path, dll_path_len, NULL);
    // step3:获取LoadLibraryA地址
  auto load_func = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
    
    // step4:执行远程线程
  HANDLE remote_thread = CreateRemoteThread(pro, NULL, 0, (LPTHREAD_START_ROUTINE)load_func, remote_buf, 0, NULL);
    // step5:等待执远程线程行完毕
    WaitForSingleObject(remote_thread, 10000);
  return true;
}

远程线程注入dll,就是在目标进程中创建一个线程,执行LoadLibrary,加载我们的dll。

2.1、写入线程函数的参数

  // step1:在目标进程申请内存  
  int dll_path_len = strlen(dll_path )+1;
  void* remote_buf = VirtualAllocEx(pro, NULL, dll_path_len, MEM_COMMIT, PAGE_READWRITE);  

  // step2:在目标进程写入dll路径
  BOOL ret = WriteProcessMemory(pro, remote_buf, (LPVOID)dll_path, dll_path_len, NULL);

首先需要把线程入口函数的参数,也就是dll的路径,写入目标进程。需要先在目标进程申请空间,再写入。

2.2、执行远程线程

// step3:获取LoadLibraryA地址
  auto load_func = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
    
    // step4:执行远程线程
  HANDLE remote_thread = CreateRemoteThread(pro, NULL, 0, (LPTHREAD_START_ROUTINE)load_func, remote_buf, 0, NULL);
    // step5:等待执远程线程行完毕
    WaitForSingleObject(remote_thread, 10000);

我们需要在目标进程中获取LoadLibrary的地址,因为LoadLibrary在kernel32.dll里,加载比较早,所以在每个进程内地址都一样,所以我们可以在本进程获取直接使用。

然后调用CreateRemoteThread执行远程线程,再调用WaitForSingleObject等待执行结束。

3、dll实现

3.1、dll入口函数

每个dll都有一个入口函数DllMain,在dll加载时会调用,我们把hook操作写在这里。

static bool init = false;
    if (!init) {
        init = true;
        // 打开控制台
        if (AllocConsole())
        {
            freopen("CONOUT$", "w", stdout);
            freopen("CONIN$", "r", stdin);
            SetConsoleTitleA("Console");
            SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
            printf("dll injectok!\n");
        }
        {
            // 制作跳板
            xx_mem_unprotect(tra_cw, 1024);
            xx_make_trampoline(&CreateProcessW, tra_cw, 0xf);
            // HOOK
            xx_mem_unprotect(&CreateProcessW, 1024);
            xx_setjmp(&CreateProcessW, &MyCreateProcessW);
        }
    }

先打开一个控制台,在控制台展示hook的信息。然后再进行hook,为了防止多次执行,使用static变量控制一下。

3.3、hook CreateProcess

char tra_cw[1024];
BOOL WINAPI MyCreateProcessW(
    _In_opt_ LPCWSTR lpApplicationName,
    _Inout_opt_ LPWSTR lpCommandLine,
    _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
    _In_ BOOL bInheritHandles,
    _In_ DWORD dwCreationFlags,
    _In_opt_ LPVOID lpEnvironment,
    _In_opt_ LPCWSTR lpCurrentDirectory,
    _In_ LPSTARTUPINFOW lpStartupInfo,
    _Out_ LPPROCESS_INFORMATION lpProcessInformation
) {
    time_t now = time(nullptr);
    printf("================\n");
    printf("%s", ctime(&now));
    wprintf(L"execute=%s\npara=%s\n\n" ,lpApplicationName,lpCommandLine );
    auto ori = xx_trampoline_to_func(&CreateProcessW, tra_cw);
    return (*ori)(lpApplicationName,
        lpCommandLine,
        lpProcessAttributes,
        lpThreadAttributes,
        bInheritHandles,
        dwCreationFlags,
        lpEnvironment,
        lpCurrentDirectory,
        lpStartupInfo,
        lpProcessInformation);
}

hook以后,打印信息,再调用原函数,毕竟我们只是监控,如果想组织,就需要再额外加一些逻辑了。

4、远程线程+hook的其它应用

二者其实可以实现很多有意思的东西:可以hook connect、recv、send来监控网络流量;外挂也可以靠注入+hook实现外挂功能。大家可以开动脑筋做一些有意思的小程序。

最后,东北码农,求关注、点赞、转发,谢谢~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
x64进程远程hook,x64_远程调用函数,源码更新V1.8.2:2021/4/12 源码为下方连接帖子后续更新内容: 浅谈64位进程远程hook技术: https://bbs.125.la/forum.php?mod=viewthreadtid=14666356extra= 不管您是转载还是使用请保留版权,源码在精益论坛免费发布本人未获利,请不要用于非法途径。 --------------------------------------------------------------- 2021/4/12 模块源码 v1.8.2更新 1:修复 x64_远调用函数()在 易语言 主线程调用时造成消息无法回调,导致易语言主线程窗口卡死的问题。      感谢楼下易友发现的BUG,已经第一时间更新 2021/4/12 模块源码 v1.8.1更新 1:修复 hook全部卸载时的流程写法的一个错误,由于句柄的提前关闭导致多个hook点卸载不干净的问题 2:改写了消息回调时线程传参的代码优化,优化了其他一些小问题 3:  鉴于很多朋友需要,改写了模块自带实列,对TCP,UDP的两组封包函数做了hook实列写法 4:列子中同样增加对x64_远调用函数()的应用写了几个列子,如使用套接字取得本地或远端IP端口API调用的的应用实列 5:本hook模块不支持非模块内存区hook,如申请的动态分配页等,不是不能支持,只是觉得没有任何意义,对这方面有需求的,自行改写模块源码使用 提醒:hook回调函数中尽量减少耗时代码,时间越长返回越慢,回调中谨慎操作控件,如必须要用到可参考源码中实列写法采用线程操作 历史更新 --------------------------------------------------------------- 2021/3/1   模块源码v1.6更新: 1:修复  x64_远程调用函数()命令,在没有提供 寄存器 参数时,没有返回值的BUG。 --------------------------------------------------------------- 2021/2/28 模块源码v1.5更新: 一:修复win7 64位系统下枚举模块 出现部分模块长度出现负数的问题,从而导致部分win7用户不能使用 二:强化 远程hook64指令_安装 的稳定性:        1,穿插代码中增加对标志位的保护,避免hook位置长度下一条指令为跳转时产生跳转错乱的问题,强化了hook任意位置的定位        2,因为穿插代码中会调用API函数,而64位汇编必须遵守栈指针16字节对齐,故对穿插代码进行栈指针16字节对齐,增强稳定性        3,hook指令安装支持长度由6-127字节 变动 为 6-119字节,原因么没必要说了,代码优化造成的,稍微少了一点无所谓了        4,对模块回调进行了适当优化处理,增强稳定性 三:应支持的朋友需要故增加 x64_远程调用函数()命令,易语言可以直接远call64进程,且无需写汇编代码或机器码指令,支持15个参数,支持返回值,支持16个通用寄存器全部取得返回值       该功能调用即16字节栈对齐,不要用户管堆栈,代码内部构成,远线程执行,你只需要知道call有几个参数,需要什么寄存器,对应提供即可。 四:有朋友说原模块x64英文看了烦,那好吧就给改成了中文标识,弄得我自己也不习惯 五:源码内列子改了改,可以自己看,需要注意的是模块注释的很详细,使用前最好看一看,尤其是hook回调接口的写法和安装的写法最好按照模块列子中的写法来,除非你能把64hook模块组看懂一遍,对于一些对本模块一知半解的朋友请不要乱改乱发,这个模块我会继续增强的,只是工作原因时间有限,只能一点一点来

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值