吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

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

[CTF] 记一次逆向工程作业——SMC代码自修改程序的逆向分析

[复制链接]
sandoth 发表于 2020-5-22 12:54
本帖最后由 sandoth 于 2020-5-22 15:34 编辑

第一次发帖,由于刚开始学习逆向工程,所以文中可能有些错误或者描述不完善的地方,欢迎大家在评论中批评指正或者提出问题进行讨论。

环境

主机:Windows10 64位 专业版
虚拟机软件:VMWare 15.1.0<br>虚拟机环境:Windows XP
软件:IDA VSCode Notepad++
编程语言:Python3 C/C++
文件:7-3.exe SMC.idc

SMC.zip (30.98 KB, 下载次数: 31)

概览

使用IDA打开7-3.exe,查看程序逻辑,并对部份意义明确的变量重命名,以便分析。

0x01

首先分析开头的汇编程序可知,程序在一开始要求用户输入字符串,即flag,对输入的flag求取长度,当flag长度length=28(0x1C)时,程序跳转至loc_40107F

mov     edx, [ebp+length]
movsx   eax, [ebp+edx+var_69]
cmp     eax, '7Dh'  //'}'
jnz     short loc_4010DD

由上述可知,flag长度为28,并且最后一个字符为:}  

0x02

loc_40109E

cmp     [ebp+var_70], 43h
jge     short loc_4010BC

显然,右侧框图为循环,并且var_70充当了计数的作用,对byte_414C3C进行了处理,通过相应的解密函数,我们可以得出解密的结果,可以看出,结果为一个函数,通过IDA的函数构建功能,我们可以得到sub_414C3C

上述循环结束后,程序将byte_414C3C转化为sub_414C3C。在loc_4010BC

mov     dword ptr [ebp-6Ch], offset sub_414C3C  //转化后汇编代码,截图为转化前
mov     esi, esp
push    offset unk_414BE0
lea     edx, [ebp+flag]
push    edx
call    dword ptr [ebp-6Ch]

程序调用了解密出的函数sub_414C3C,传入了flagunk_414BE0两个参数。

我们进入函数sub_414C3C

由汇编代码可知arg_0,即flag前五位分别需要满足的条件,使用IDA自带的ASCII转字符功能可以得到对应的字符,结果为flag{

剩余部分,即为对传入的第二个参数unk_414BE0的解密和重新调用。通过阅读解密的汇编代码,我们可以通过SMC.idc中的解密函数xor_setp2()进行解密,将unk_414BE0转化为函数sub_414BE0,由sub_414C3C的逻辑知,有两个参数传入了sub_414BE0,分别为flagunk_414A84,其中flag已不包括前五个字符。

0x03

进入sub_414BE0进行分析,其中arg_0即为flag


图中存在一个循环,内容为对flag的前四位的判断,由此我们可以再得到flag的四位字符。

判断情况为,将的flag的每8位与0xCC异或,得出的结果分别与var_8中的对应8位,即两个十六进制数相比,只有四次比较均通过,才能够正常执行函数的剩余部分。需要考虑数据的端存储方式,下面给出解密程序的C语言实现

int decode0x03(){
    int ch = 0;
    int arr[4] = {0x93,0xA9,0xA4,0x98};
    for (int i = 3; i >= 0; i--)
    {
        ch = (arr[i]^0xCC);
        printf("%c",ch);
    }
    return 0;
}

输出结果为

The_

下面分析函数sub_414BE0unk_414A84的处理情况


和之前分析过得情况相似,均是先将其解密,形成一个可使用的函数,然后再进行调用。同样,我们根据解密的过程使用SMC.idc中的函数xor_setp3()进行解密,得到函数sub_414A84,传入参数为flagunk_414A30,这里的flag已经不包括前九位了。

0x04

进入函数sub_414A84,由于数据有些复杂,这里使用IDA的伪代码查看功能进行分析。这里截取部分标志性的代码片段进行分析。

//将字母、数字、部分字符的ASCII码存入数组v20中
v2 = 65;
v3 = 0;
do
  *((_BYTE *)&v20 + v3++) = v2++;
while ( v2 <= 90 );
v4 = 97;
do
  *((_BYTE *)&v20 + v3++) = v4++;
while ( v4 <= 122 );
v5 = 48;
do
  *((_BYTE *)&v20 + v3++) = v5++;
while ( v5 <= 57 );
*(__int16 *)((char *)&v20 + v3) = 0x2F2B;

在此代码块中,我们可以看到,程序初始化了一个数组v20,并将所有的数字和字母以及一部分字符的ASCII码值存在了v20中。

//rename "a1" as "flag"
//对每三个字符进行一组处理,共处理flag中的六个字符
do
{
  v8 = *(_BYTE *)(flag + v7 + 1);
  v9 = *(_BYTE *)(flag + v7 + 2);
  v10 = *(_BYTE *)(flag + v7) & 3;
  v11 = (unsigned int)*(_BYTE *)(flag + v7) >> 2;
  v7 += 3;
  *v6 = *((_BYTE *)&v20 + v11);
  v6[1] = *((_BYTE *)&v20 + (((unsigned int)v8 >> 4) | 16 * v10));
  v6[2] = *((_BYTE *)&v20 + (((unsigned int)v9 >> 6) | 4 * (v8 & 0xF)));
  v6[3] = *((_BYTE *)&v20 + (v9 & 0x3F));
  v6 += 4;
}
while ( v7 < 6 );
//对flag中的下两个字符进行处理
if ( v7 < 8 )
{
  v12 = *(_BYTE *)(v7 + flag);
  *v6 = *((_BYTE *)&v20 + ((unsigned int)*(_BYTE *)(v7 + flag) >> 2));
  v13 = v12 & 3;
  if ( v7 == 7 )
  {
    v6[1] = *((_BYTE *)&v20 + 16 * v13);
    v6[2] = 61;
  }
  else
  {
    v14 = *(_BYTE *)(v7 + flag + 1);
    v6[1] = *((_BYTE *)&v20 + (16 * v13 | ((unsigned int)*(_BYTE *)(v7 + flag + 1) >> 4)));
    v6[2] = *((_BYTE *)&v20 + 4 * (v14 & 0xF));
  }
  v15 = v6 + 3;
  *v15 = 61;
  v6 = v15 + 1;
}

此代码块为对flag的处理过程,对于前六个字符,程序将其均分为两份,即每三个字符为一个部分。首先,将第一个字符存入v10,第二个字符存入v8,第三个字符存入v9

v11代表将flag的第一个字符的二进制表示右移两位,即取左侧六位存入v11,而后将其在v20数组中对应的字符存在了数组v6中;

同理分析得,v6[1]代表flag第一个字符的后两位与第二个字符的前四位二进制数拼接后在v20中对应的字符;

v6[2]代表flag第二个字符的后四位与第三个字符的前两位二进制数拼接后在v20中对应的字符;

v6[3]代表flag第三个字符的后六位二进制数拼接后在v20中对应的字符。

第一轮的处理结束,第二轮将会处理接下来的三位字符,处理方式与上述过程类似,不再重复描述。

当完成前六位字符的处理过后,数组v6中已经根据数组v20的映射关系存入了八位字符。开始处理第七和第八位字符。

if中,同样根据v20的映射关系,将第七位字符的前六位二进制表示所代表的字符存入v6中;将第七位字符的后两位与第八位字符的前四位拼接而成的六位二进制数根据数组v20所对应的字符存入v6中;最后剩余第八个字符的后四位经过乘4运算在后面补两个零,同样构成一个六位二进制数,再根据数组v20的对应方式,将对应字符存入v6;最后再将=存入v6

通过上面的分析,此函数的加密过程即为Base64的加密过程,通过加密flag后生成的字符串与所给字符串相比较,只有符合时才能够正常运行后面的程序。

开头有:

mov     [ebp+var_10], 68566D63h
mov     [ebp+var_C], 304E4562h
mov     [ebp+var_8], 3D386C52h

在对flag的判断部分

可以看到,由于地址的连续性,开头的三个变量var_10 var_C var_8与经Base64编码过的flag进行对比,当所有的对比均通过后才可以正常执行接下来的操作。通过IDA的ASCII转字符功能,我们可以得到

mov     [ebp+var_10], 'hVmc'
mov     [ebp+var_C], '0NEb'
mov     [ebp+var_8], '=8lR'

考虑数据的端存储方式,正确的Base64编码后的字符串应为cmVhbEN0Rl8=,通过解码,即可得到flag的一部分,下面给出Python3的解密实现

import base64
undecoded_base64 = b'cmVhbEN0Rl8='
des2 = base64.b64decode(undecoded_base64)
print(str(des2).strip('b').strip('\''))

输出为

realCtF_


同样,在最后也存在对传入参数unk_414A30的处理,同样,我们根据解密的过程使用SMC.idc中的函数xor_setp4()进行解密,得到函数sub_414A30,传入参数只剩下flag,这里的flag已经不包括前十七位了。

0x05

进入函数sub_414A30进行分析,下为开头的数据定义。

var_C= dword ptr -0Ch
var_8= dword ptr -8
var_4= word ptr -4
var_2= byte ptr -2
arg_0= dword ptr  8
------------部分省略------------
mov     [ebp+var_C], 7574766Bh
push    esi
push    edi
mov     [ebp+var_8], 68344360h
or      edx, 0FFFFFFFFh
mov     [ebp+var_4], 6F22h

可知var_C var_8 var_C地址是连续的。

loc_414A68部分即为flagvar_C的对比过程,可知flag的每一个字符需要与var_C存在一个关系

flag[i] = var_C[i] - 1;

根据比较过程和已知数据并考虑过数据的端处理情况后,这里给出解密函数的C语言实现

int decode0x05(){
    int str[10] = {0x6B,0x76,0x74,0x75,
                    0x60,0x43,0x34,0x68,
                    0x22,0x6F};
    for (int i = 0; i < 10; i++)
    {
        str1[i] = str1[i]-1;
        printf("%c",str1[i]);
    }
    return 0;
}

输出为

just_B3g!n

测试

综合以上的分析,我们可以给出程序的flag

flag{The_realCtF_just_B3g!n}

总结

在逆向的过程中,要注意数据的端存储方式,以保证正确识别flag内容,避免由字符顺序带来的不必要的干扰。

其次,不能过分依赖伪代码,有些情况下伪代码可能会因为表示方式而对解决问题产生一定的误导作用。譬如说,我在解决0x03部分的问题时就是被伪代码迷惑,由于表达与理解的差异而无法正确解决,最后还是通过查看汇编代码正确厘清了逻辑关系,并能够完成解密;0x05部分同样也是如此,相对于伪代码,汇编代码的表述更加准确,而不容易出现理解的错误。同时,在分析汇编代码时,能够更好地理解数据在内存中的存储方式,帮助我们理解伪代码中的变量使用,其作用也是很大的,例如在分析0x04时,就是通过伪代码得出Base64这一重要突破点的。因此要灵活地使用。

免费评分

参与人数 1威望 +1 吾爱币 +20 热心值 +1 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

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

 楼主| sandoth 发表于 2020-5-22 15:44
idc文件可以在FIle->Script File加载,使用此文件解密时注意修改文件内调用的函数,以保证解密的是当前需要解密的内容
真诚真诚 发表于 2020-5-22 15:14
pizazzboy 发表于 2020-5-22 15:16
fightingman 发表于 2020-5-26 13:11
楼主在哪读书,还教逆向。佩服佩服
 楼主| sandoth 发表于 2020-5-26 17:02
fightingman 发表于 2020-5-26 13:11
楼主在哪读书,还教逆向。佩服佩服

我们老师也说很少有学校开逆向工程这门课,说实话我也挺吃惊的。
pantherTL 发表于 2020-6-5 08:39
感谢分享,每次都有新的收获。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-12-27 18:05

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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