我是木头。 发表于 2019-9-13 17:41

CG CTF WxyVM

## 吾爱破解,初来报道!(可能有些地方分析得不太正确,还望多宽(容)待!)
这道题我做了两天,卡死在了写脚本上了,不断修改脚本,过程中学到了挺多!
<!-- more-->
## 寻找关键:
> 记事本打开发现是elf文件,然后在ubuntu中运行,提示让我们输入flag,随便输入,回复我们:wrong于是拖入IDA F12

```
LOAD:0000000000400238        0000001C        C        /lib64/ld-linux-x86-64.so.2
LOAD:0000000000400349        0000000A        C        libc.so.6
LOAD:0000000000400353        00000005        C        puts
LOAD:0000000000400358        00000007        C        strlen
LOAD:000000000040035F        00000006        C        scanf
LOAD:0000000000400365        00000012        C        __libc_start_main
LOAD:0000000000400377        0000000F        C        __gmon_start__
LOAD:0000000000400386        0000000C        C        GLIBC_2.2.5
.rodata:0000000000400848        0000000E        C       
.rodata:0000000000400856        00000011        C        input your flag:
.rodata:000000000040086A        00000008        C        correct
.rodata:0000000000400872        00000006        C        wrong
.eh_frame:000000000040091F        00000006        C        ;*3$\"
```
> 找到input your flag 鼠标双击它 来到它的位置,然后按X查看哪里引用它了
然后就来到了main函数了 F5 看下主函数的反编译

```
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
char v4; //
signed int i; //

puts("");
puts("input your flag:");
scanf("%s", &byte_604B80);                  // 输入字符串存在 604B80处
v4 = 1;
sub_4005B6();
if ( strlen(&byte_604B80) != 24 )             // 604B80处的字符串长度为24
    v4 = 0;
for ( i = 0; i <= 23; ++i )
{
    if ( *(&byte_604B80 + i) != dword_601060 )// 604B80处的每个字节 与601060处每个双字的最后两位(即字节)要相等
      v4 = 0;
}
if ( v4 )
    puts("correct");
else
    puts("wrong");
return 0LL;
}
```
> 这里注意下601060存的是24个双字类型的数据,所以与604B80(存的是字节类型)做比较时 只需比较的是601060处每个双字的最后两位(即字节)<br>
我们再看下 sub_4005B6()函数做了什么

```
__int64 sub_4005B6()
{
unsigned int v0; // ST04_4
__int64 result; // rax
signed int i; //
char v3; //

for ( i = 0; i <= 14999; i += 3 )             // 6010C0地址存放着 15000字节大小的 16进制数3个为1组
{
    v0 = byte_6010C0;                        // v0=每组的第一个   16进制数
    v3 = byte_6010C0;                  // v3 为每组的第三个   16进制数
    result = v0;                              // result赋初值 每组的的第一个16进制数
    switch ( v0 )                               // 根据每组的第一个 16进制数 决定接下来进行什么操作(算法)
    {
      case 1u:
      result = byte_6010C0;            // result = 每组的第二个 16进制数
      *(&byte_604B80 + result) += v3;         // 604B80是我们输入字符串存放的地址(指针)
                                                // 所以这里就相当与 604B80=604B80+v3
      break;
      case 2u:                                  // 同理 604B80=604B80-v3
      result = byte_6010C0;
      *(&byte_604B80 + result) -= v3;
      break;
      case 3u:                                  // 同理 604B80=604B80^v3
      result = byte_6010C0;
      *(&byte_604B80 + result) ^= v3;
      break;
      case 4u:
      result = byte_6010C0;            // 同理 604B80=604B80*v3
      *(&byte_604B80 + result) *= v3;
      break;
      case 5u:
      result = byte_6010C0;            // 下面等号右面的意思:604B80,byte_6010C0==V3
      *(&byte_604B80 + result) ^= *(&byte_604B80 + byte_6010C0);// 这句代码意思:
                                                // 604B80=604B80^604B80
                                                //
                                                // 这里byte_6010C0的意思其实还是上面的V3
      break;
      default:
      continue;
    }
}
return result;
}
```
## 分析:

```
函数的意思:
根据6010C0处 6010C06010C0 6010C0...6010C0来决定
对604B80的24个16进制数(即我们输入的字符串)进行 不同的操作
而操作后的604B80地址(指针)存放的24个16进制数(即我们输入的字符串经函数ub_4005B6()加密了)
最后604B80处的每个16进制数(字节)再与601060处每个双字的最后两位16进制数(即字节)要相等
```
## 逆向:

```
我们一切都逆着进行
我们的操作还是根据6010C0处 6010C06010C0 6010C0...6010C0来决定
对604B80的24个16进制数(加密后的字符串==601060处每个双字的最后两位16进制数)进行 不同的操作
不过从14997到0进行循环操作
+换成-,*换成/亦或还是亦或(举例:0x8^0x3=0xB0xB^0x3=0xB0xB^0x8=0x3)
604B80=604B80-v3
604B80=604B80+v3
604B80=604B80^v3
604B80=604B80/v3
604B80=604B80^604B80
```


## 脚本

```
#coding:utf8
da=open('export_results','rb')#导出的二进制形式的15000字节的数组
bianhua=
#bianhua对应的是 601060处的数据,每个双字的最后两位16进制数手动敲上去的
#流下没有技术的泪。
dashuzu=[]
for i in range(0,15000):
        temp=da.readline(1)
        dashuzu.append(ord(temp))
#print(dashuzu)
da.close()
for i in range(14997,-1,-3):
        v0=dashuzu
        v3=dashuzu
        result=v0
        if v0==1:
                result=dashuzu
                bianhua-=v3
        elif v0==2:
                result=dashuzu
                bianhua+=v3
        elif v0==3:
                result=dashuzu
                bianhua^=v3
        elif v0==4:
                result=dashuzu
                bianhua/=v3
        elif v0==5:
                result=dashuzu
                bianhua^=bianhua]
        else:
                continue
#print (bianhua)
flag=''
for j in bianhua:
        flag+=chr(j%256)#保证数据可以正常转成字符
print flag
# nctf{Embr4ce_Vm_j0in_R3}
```
## 总结:

```
真的好菜,要抓紧了,超越萝卜 /(刷题是我快乐,或许吧,哈哈!)
```

!(https://s2.ax1x.com/2019/08/06/ehY4nP.jpg)

hnwq 发表于 2019-9-14 10:33

学习了,谢谢分享

plwt 发表于 2019-9-14 15:12

支持楼主继续进步

我是木头。 发表于 2019-9-16 19:20

plwt 发表于 2019-9-14 15:12
支持楼主继续进步

谢谢,会的!

我是木头。 发表于 2019-9-16 19:21

hnwq 发表于 2019-9-14 10:33
学习了,谢谢分享

谢谢支持!!!

stone2333 发表于 2019-9-22 22:34

小白请问一下如何将这道题中 6010c0 处的数据导出
页: [1]
查看完整版本: CG CTF WxyVM