MENU

记录对SmartBot的逆向

August 8, 2020 • Read: 938 • Reverse

起因:本来想试试看SB的,结果加载了半天没进去,就只能逆向看看他是怎么连接的。

我们先是看看是用什么写的。

查壳.png

其实我最早看的时候是用了旧版本的Exeinfope,结果只查出来是个.net编写的软件,什么壳都没显示,结果今天写文章的时候更新成了新版本的,发现直接能把壳的名字显示出来。

所以,我们还是稍微绕点弯路,看一下我刚开始是怎么看的。
那既然是用.net写的,那就直接拖进Dnspy看一看代码。

初步查看.png

嗯,明显是很严重的混淆。我们可以用de4dot拖拖看。
de4dot脱壳.png

看来de4dot也没识别出来是什么壳,但是他帮我们把上面那种恶心的混淆名称给去掉了,于是我们再次拖进去看看。
去除混淆.png

嗯,虽然代码还是乱七八糟的,但是比起之前要好多啦,但是这个代码流程被混淆了,这样子阅读的难度就大大提升了。

int num2 = enumerator.MoveNext() ? -1341126532 : -1577207623;
for (;;)
{
    switch ((num2 ^ -1746658465) % 4)
    {
    case 0:
        num2 = -1341126532;
        continue;
    case 1:
        goto IL_196;
    case 3:
    {
        KeyValuePair<int, int> keyValuePair = enumerator.Current;
        Class38.smethod_3(keyValuePair.Key, ref @struct);
        num2 = -1345980630;
        continue;
    }
    }
    goto Block_12;
}

很有意思的一个打乱流程的方法,这个只是里面的一个特别简单的流程替换,还有其他有两百多个case的无法在这里展示。
原理就是利用一个死循环,然后一个num2来控制流程。
先给num2一个初始值来表明它能进入哪个case。switch这里呢是用一个异或然后取模来确定位置。
mod的大小就取决于分裂语句的条数,比如这里就是分裂了三个语句,那么就mod 3。
这个代码正向的来看,也就是加密的过程是比较简单的,模拟一个随机数,然后异或后取模来确定位置。
但是我们反向的来看,如果要通过取模之后的数来确定原来的num是很困难的(因为取模之后数据丢失了),所以难以得到被赋值的num2的值。
所以我们可以顺着代码的顺序,正向的来推理,从赋值给num2的数字来推测代码流程。不过这个过程是比较繁琐的,我是通过计算器来解决的(懒得写个程序来算了)。

但是既然是写文章,还是要把最简单的方法呈现给大家,既然上面的已经查出来是是ConfuserEx壳了,那我们就先搜索看看有没有什么脱壳机可以去这层混淆。功夫不负有心人,在吾爱发现了这款壳的脱壳机,前面把我折磨了半天的switch流程居然可以直接解密出来。根据帖子里面的方法,我得到了一个混淆没那么严重的程序。

接下来就是一顿分析研究,我是从关键词和对每个程序集都瞟一眼这种方法。得到解密方法之后,利用Wireshark看数据包来搞明白这个软件的流程的。

说一下我的研究结果吧。
1.对用户Key的保存方法,是用了AES加密。
大概就是下面的逻辑,最里面的一层是用他写的一个秘钥,然后外面一层是用的你的机器用户名称加上机器名称(Environment.UserName + Environment.MachineName)
"EC:" + AES("LC:" + AES($KEY))

2.与sb服务器的交互,这里反倒是比较危险的地方,居然没有加密,只是用了一个很简单的压缩算法。

3.需要打开加载这么久的原因是注入的payload是从完全从服务器返回的,每次加载的时候都需要从服务器接收一个差不多240KB的文件,然后利用本地的Loader.dll文件进行注入dll,注入进去之后就是利用与注入游戏的payload进行交互。

4.为什么sb这么流畅就可以解释了,hb对hs的操作都是一个外部软件,然后通过hook来进行读取和操作,但sb就很简单粗暴了,直接注入进去hook dx的函数,相当于hs的所有dll函数都可以直接用,不用像hb那么麻烦,而且效率还很高,操作就像是游戏自己的操作一样,而兄弟每次都要读取大量的数据,所以每次都会卡顿,可以考虑让兄弟直接利用这个payload操作,这样的话以后游戏有什么更新也就无忧了,而且速度提高很多。每次payload得到场面之后就会向客户端发送场面数据,客户端得到场面数据之后再想服务器发送。服务器计算完成之后再把这个操作的数据返回到客户端,客户端再给payload进行操作。而这个返回的操作都是一次性的连贯操作(到有随机事件发生为止),如果有随机事件发生则重新请求数据,这就是sb打牌流畅的原因。但是现在hb操作都是每一部操作都会进行检验场面是否与预料的是否一致。如果要移植的话,就要确定hb写的代码与模拟的一致,并且每次有随机操作的时候都要标记。其实我认为因为随机操作所导致的之后的场面都很难计算。现在兄弟对于随机的操作都是先假定一个固定值,从而会导致连锁的错误计算。所以我认为如果要计算出最好的场面,那么就要考虑全部的随机结果,但是这个考虑的分支实在是太大了,只能利用一些我不太懂的算法,比如Alpha go的算法MCTS 蒙特卡洛搜索树。所以这个改进算法的过程就只能先放一放了。

最后贴一个炉石机器人比赛的网址,有兴趣的可以去研究一下别人写的AI。
炉石机器人比赛:炉石传说AI

写的很仓促,过程中通过了搜索引擎查了很多信息,前前后后两天多的时间也让我学到了很多知识,文章有些地方描述的不流畅,希望可以谅解。

Last Modified: November 2, 2020
Archives QR Code Tip
QR Code for this page
Tipping QR Code
Leave a Comment

3 Comments
  1. saki saki

    博主 这个最后的炉石AI比赛网站好像挂了 还有什么别的学习的地方吗

  2. arnoldwang arnoldwang

    想问问hook dx是什么意思,对于控制炉石进程一窍不通,如果能加个微信讨论一下,最好不过。

    1. wjh wjh

      @arnoldwanghook dx可以有机会在每一帧都接管到程序的控制权