吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4488|回复: 6
收起左侧

[CTF] CG CTF WxyVM

  [复制链接]
我是木头。 发表于 2019-9-13 17:41

吾爱破解,初来报道!(可能有些地方分析得不太正确,还望多宽(容)待!)

这道题我做了两天,卡死在了写脚本上了,不断修改脚本,过程中学到了挺多!
<!-- 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   [WxyVM 0.0.1]
.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; // [rsp+Bh] [rbp-5h]
  signed int i; // [rsp+Ch] [rbp-4h]

  puts("[WxyVM 0.0.1]");
  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[i] )// 604B80处的每个字节 与601060处每个双字的最后两位(即字节)要相等
      v4 = 0;
  }
  if ( v4 )
    puts("correct");
  else
    puts("wrong");
  return 0LL;
}

这里注意下601060[i]存的是24个双字类型的数据,所以与604B80i做比较时 只需比较的是601060处每个双字的最后两位(即字节)<br>
我们再看下 sub_4005B6()函数做了什么

__int64 sub_4005B6()
{
  unsigned int v0; // ST04_4
  __int64 result; // rax
  signed int i; // [rsp+0h] [rbp-10h]
  char v3; // [rsp+8h] [rbp-8h]

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

分析:

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

逆向:

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

脚本

#coding:utf8
da=open('export_results','rb')#导出的二进制形式的15000字节的数组
bianhua=[0xC4,0X34,0x22,0xB1,0xD3,0x11,0x97,0x7,0xDB,0x37,0xC4,0x6,0x1D,0xFC,0x5B,0xED,0x98,0xDF,0x94,0xD8,0xB3,0x84,0xCC,0x8]
#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[i]
    v3=dashuzu[i+2]
    result=v0
    if v0==1:
        result=dashuzu[i+1]
        bianhua[result]-=v3
    elif v0==2:
        result=dashuzu[i+1]
        bianhua[result]+=v3
    elif v0==3:
        result=dashuzu[i+1]
        bianhua[result]^=v3
    elif v0==4:
        result=dashuzu[i+1]
        bianhua[result]/=v3
    elif v0==5:
        result=dashuzu[i+1]
        bianhua[result]^=bianhua[dashuzu[i+2]]
    else:
        continue
#print (bianhua)
flag=''
for j in bianhua:
    flag+=chr(j%256)#保证数据可以正常转成字符
print flag
# nctf{Embr4ce_Vm_j0in_R3}

总结:

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

ehY4nP.jpg

免费评分

参与人数 2吾爱币 +7 热心值 +2 收起 理由
Sound + 6 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
朱朱你堕落了 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

hnwq 发表于 2019-9-14 10:33
学习了,谢谢分享
plwt 发表于 2019-9-14 15:12
 楼主| 我是木头。 发表于 2019-9-16 19:20
 楼主| 我是木头。 发表于 2019-9-16 19:21
hnwq 发表于 2019-9-14 10:33
学习了,谢谢分享

谢谢支持!!!
stone2333 发表于 2019-9-22 22:34
小白请问一下如何将这道题中 6010c0 处的数据导出
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-17 02:48

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表