关于 DreamCat

主题名称:DreamCat | 版本:3.0.240224

主题开发:HanFengA7 | CornWorld

Designed by HanFengA7 Power by Typecho

Copyright © 2015-2024 by LychApe All rights reserved!

menu
refresh

反汇编真是太难了 WriteUp

作者: ciaoℒy

时间:

题目链接: SOCTF - 综合实训平台

下载题目附件, 打开发现为asm.exe. 使用ExeInfoPe查看其为win32应用. greps命令找不到flag字符串, 使用IDA.exe尝试打开进行静态分析.

ida静态分析

主函数如图示:

image-20210803162523811

双击_main_0跳转, 尝试追踪其执行过程.

image-20210803162716923

在过程_main_0中发现存在完整的交互提示语, 根据该过程可大致看出该程序的运行流程. 在call sub_401005处进行的函数调用直接决定了程序运行流, 由此断定该调用与输入处理流程直接相关. 双击sub_401005跳转到该调用处.

一直追踪程序跳转, 直到在子调用sub_401020处发现程序主要逻辑. 按下f5键尝试使用IDA翻译C语言代码, 去掉多余的变量声明环节, 可以得到主要逻辑代码如下:

signed int sub_401020()
{
  // .......
  scanf("%s", &v21);
  if ( strlen(&v21) != 27 )
    return 1;
  for ( i = 0; *(&v21 + i); ++i )
  {
    for ( j = 0; j < 13; ++j )
      *((_BYTE *)v14 + j + i) = *((_BYTE *)&v17 + j) ^ *(&v21 + i);
  }
  for ( k = 0; v14[k]; ++k )
  {
    if ( v14[k] != *(&v4 + k) )
      return 1;
  }
  return 0;
}

可以看出, v21为用户输入内容的buffer, 输入长度为27. 将用户输入作为明文的话, v17相当于异或加密的key, v14相当于加密后的密文, v4相当于正确的密文. 根据异或加密的特点, 按照该程序逻辑将v4v17进行异或运算即可获得本题的flag. 进一步分析上述代码逻辑, 发现v14中存储的结果实际上分为两部分:

  1. v21(用户输入)中的每一个字符与v17的第一个值进行异或的运算结果;
  2. v21(用户输入)的最后一个字符与v17中其余12个元素均进行一次异或运算的结果.

即:

0 1 ... 26 27 ... 39
v21[0] ^ v17[0] v21[1] ^ v17[0] ... v21[26] ^ v17[0] v21[26] ^ v17[1] ... v21[26] ^ v17[12]

因此, 只需要拿到v17[0]v4即可.

x64dbg进行动态分析

设置断点

asm.exe放到x64dbg中进行动态调试, 尝试拿到上述v14v17的内容.

根据ida的静态分析结果, 在x64dbg中跳转到地址0x401161处, 按照执行顺序向下寻找代码xor edx, ecx, 在该代码处设置断点. 在这里可以获取到v17[0]

image-20210803171204297

跳转到地址0x4011B4处, 向下寻找代码cmp edx,dword ptr ss:[ebp+ecx*4-D0], 在该代码处设置断点. 在这里可以获取到v4.

image-20210803171843092

设置好断点后如图:

image-20210803172510707

因为在0x4011D7处匹配一定会出现失败, 为了防止程序往下运行直接退出, 所以在0x4011EB处设置了断点.

动态调式

在x64dbg中运行程序, 输入测试用flag: flag{123456789012345678901} (这里需要保证输入的flag长度为27). 程序正常运行到断点0x401180处, 此时在寄存器窗口中查看ecx寄存器的值为'1', 该值即为v17[0]. (在这里还能看到, edi寄存器处显示出了v17中的所有元素123456789!@#)

进行0x401180处断点, 使程序正常运行, 跳出该循环并断在0x4011D7处.

在x64dbg处运行命令ebp+ecx*4-D0, 得到v4的起始地址(0x19FE39). 在内存窗口中跳转到该地址处, 可以观察到该处内存如下所示:

0019FE38  00 57 5D 50 56 4A 00 03 02 05 04 07 06 09 08 01  .W]PVJ..........  
0019FE48  00 03 02 05 04 07 06 09 08 01 00 4C 4F 4E 49 48  ...........LONIH  
0019FE58  4B 4A 45 44 4D 5C 3D 5E 00 00 00 00 00 00 00 00  KJEDM\=^........  

可以看出, 自0x57到0x5E处, 共有39个数据. 该39个数据即为v4的值. 同时, 经过对字符串flag{}与字符串'1'进行异或运算, 可以确定0x57 0x5D 0x50 0x56 0x4A 0x4C即为flag{}的"密文", "ONIH....^"即为字符'}'v17后续12个元素进行异或运算的"密文". 由此可以确定, 该处内存数据即为获取正确flag所需要的"正确密文".

求解flag

按照上文分析, 构造如下代码, 运行并得到flag:

let enc = [0x57, 0x5D, 0x50, 0x56, 0x4A, 0x50, 0x42, 0x5C, 0x6E, 0x00, 0x42, 0x6E, 0x47, 0x02, 0x43, 0x48, 0x6E, 0x55, 0x00, 0x57, 0x57, 0x54, 0x43, 0x02, 0x5F, 0x45, 0x4C];
let flag = "";
let key = "1".charCodeAt();
enc.forEach(ele => flag += String.fromCharCode(ele ^ key));
console.log(flag);

得到flag{asm_1s_v3ry_d1ffer3nt}


#本文链接:https://blog.chaol.top/archives/35.html
#本文采用 CC BY-NC-SA 4.0 协议进行许可
#如无特别声明,该文章均为 ciaoℒy 原创,转载请遵循 署名-非商业性使用 4.0 国际(CC BY-NC 4.0)协议,即转载请注明文章来源。
#最后编辑时间为: 2021 年 08 月 07 日
WriteUp
none

create 添加新评论


account_circle
email
language
textsms



加我的QQ
加我的微博
加我的支付宝
加我的微信