Panel 发表于 2022-9-3 10:04

记网鼎杯一道逆向题



##### 先来一丢丢废话(勿喷):很久没发帖的原因是大三时间比较紧,一遍学内核一遍还要上班,这篇帖子是单独早起搞得,哈哈哈

### 1.查壳 UPX3.96


## 2.脱壳

#### 载入x64dbg


#### 有个小细节,载入x64dbg的时候不是程序的入口点,所以咱们先让他跑一遍,跑到程序入口处


#### 看到四个连续的push,可以知道脱壳入口点就是这里了,我们执行一条push命令后使用esp定律跳过去


#### 可以看到这里连续出现了四个pop对应之前的四个push,这就很满足壳的加载到结束的特征了,再看有个jmp跳转的位置属于程序re2的领空且十个跨度很大的跳转,那咱们就跳过去,跳过去的位置90%就是oep的位置了


#### 跳过来一看就确定100%是正在oep的位置了,这就是个开了增量链接编译的特征,那我们直接使用Scylla来脱壳


#### 选择转储保存好之后,咱们再修复转储


#### 再次查壳,发现已经脱壳成功


#### 但是直接运行是运行不了的,因为x64默认随机映像地址,所以咱们得用StudyPE++来关闭一下随机基址


#### 保存好后再此查壳运行就能跑起来了

## 3.算法分析

#### 老规矩,拖进ida查看关键字符


#### 找到引用的函数去


#### 发现关键逻辑,flag验证,与用户操作的变量只有v3,那v3就是我们输入认为的flag,那按照以前我写的思路,只分析与我们有关变量参与的决定性逻辑,那就是v3参与的决定性逻辑


#### 那就只有上面两处,有小伙伴可能会问第二个标记处为什么算得上决定性逻辑,那咱们看代码

```c
if ( !v4 )
    sub_7FF6FCFD11E5(v3, 20i64);
if ( v4 == 1 )
{
    sub_7FF6FCFD11E0(aWrong);
    exit(0);
}
sub_7FF6FCFD11E0(aRight);
exit(0);
```

#### 在判断逻辑真假时,只有两种可能0和非0,那我们看在两次if判断的条件,其实就是这两种if只能成立一种,也就是0和非0(1),但是为1的时候提示了Wrong,只有为0时才提示了Right,`sub_7FF6FCFD11E5(v3, 20i64)也是决定性逻辑

#### 那接下来咱们就逆向推导算法

#### 先进入sub_7FF6FCFD11E5()函数:


#### a1,a2参与运算的也只有红框处,a1是我们输入的字符串,a2是传进来的20,那咱们又再次跟进sub_7FF6FCFD1276函数查看进一步的具体逻辑


#### 虽然我们关注的任然是a1和a2的值,但是不要搞混了,此时的a1是一个从0开始的计数器,调用者传入的j,a2则是我们输入的字符串进行运算的值,那这里逻辑就是说用与我们输入有关的字符串进行运算后和一个常量进行比较,注意这个常量是被按照dwor强转来操作的,那么我们现在就可以得到一个逻辑如下:

```c
for(int i = 0; i < 20 ; i++ )
{
   if(常量 == (用户输入+10)^0x50)
       continue;
    else
      错误
}
```

#### 那此时我们就可以通过这个逻辑把用户输入有关的字符串解出来,首先找到这个常量




#### 通常情况c的字符串都是小端序,又因为他是dword类型操作的,所以咱们得两两交换

```
int code1[]={0x4b,0x48,0x79,0x13,0x45,0x30,0x5c,0x49,0x5a,0x79,0x13,0x70,0x6d,0x78,0x13,0x6f,0x48,0x5d,0x64,0x64}
```

#### 综上,我们便得到了最后一次加密的flag,代码如下:

```
int code1[] = { 0x4b,0x48,0x79,0x13,0x45,0x30,0x5c,0x49,0x5a,0x79,0x13,0x70,0x6d,0x78,0x13,0x6f,0x48,0x5d,0x64,0x64 };
        int result = { 0 };
        for (int i=0;i<20;i++)
        {
                result = (code1 ^ 0x50) - 10;
        }
```

#### 现在我们再去找最后一个与我们加密有关的函数逻辑去:sub_7FF6FCFD1235(之前最上面的图找逻辑那里说到过)


#### a1是我们输入的字符串,每一个字符都异或才得到我们上面那不解出来的加密flag,那我们再用加密的flag异或0x66就可以得到正确的flag了

```
for (int i=0;i<20;i++)
        {
                result = result^0x66;
        }
```


## 最后

#### 最后我给出完整的解密代码

```
#include <stdio.h>
#include <windows.h>

int main()
{
        int code1[] = { 0x4b,0x48,0x79,0x13,0x45,0x30,0x5c,0x49,0x5a,0x79,0x13,0x70,0x6d,0x78,0x13,0x6f,0x48,0x5d,0x64,0x64 };
        int result = { 0 };
        for (int i=0;i<20;i++)
        {
                result = (code1 ^ 0x50) - 10;
                result = result ^ 0x66;
                printf("%c", result);
        }
        return 0;
}
```



路人王2021 发表于 2022-9-3 13:19

假装自己是高手
看了三遍
没看懂

F1ame7w7 发表于 2022-9-5 08:45

这题是网鼎青龙组的一道re,

程序64位,用的UPX壳加密,但是做了一点修改,使得原UPX工具无法脱壳,楼主直接手脱是硬本事,这里我再分享一下取巧得脱壳技巧:

CFF打开文件->进入Section Headers->将段名得FUK都改为UPX即可工具脱壳。

题目py脚本:
enc =
flag = ""
for i in enc:
    flag += chr(((i^0x50)-10)^0x66)
print(flag)

qin15528 发表于 2022-9-3 11:13

最近才听说王鼎杯,没想到今天就看见大佬分享教学了:lol

rinima 发表于 2022-9-3 11:17

感谢楼主分享

搜索曾经的回忆 发表于 2022-9-3 12:09

这题我好像做过

aspllh 发表于 2022-9-3 15:15

正需要,过来学习内容!

lAQUQ 发表于 2022-9-3 15:45

学习学习

aonima 发表于 2022-9-3 17:08

感谢分享,学习了

ljorz 发表于 2022-9-3 18:25

感谢分享

maybegood 发表于 2022-9-3 18:31

感谢分享,一起学习
页: [1] 2
查看完整版本: 记网鼎杯一道逆向题