SMC代码自修改逆向分析(仅针对汇编语言分析)

"本文详细讲述了如何通过逆向分析一步步解开SMC加密代码,涉及四层加密过程,从字符串判断、SMC加密、Base64编码到最终的自定义函数。揭示了flag:flag{The_realCtF_just_B3g!n}
摘要由CSDN通过智能技术生成

title: SMC代码自修改逆向分析
category: 逆向


写在前面

  1. 加密代码在文末附件
  2. 用到的idc解密脚本:
#include <idc.idc>

static xor_setp1(){
    auto addr = 0x00414c3c;   //这里填入要解密字节串的起始地址
    auto i = 0;
    for(i=0;addr+i<0x00414C7F;i++)   //循环结束的条件为字节串的结束地址
    {
        PatchByte(addr+i,Byte(addr+i)^0x7D);   //异或的数字根据情况修改
    }
}

static xor_setp2(){
    auto addr = 0x00414be0;   //这里填入要解密字节串的起始地址
    auto i = 0;
    for(i=0;addr+i<0x00414C3A;i++)   //循环结束的条件为字节串的结束地址
    {
        PatchByte(addr+i,Byte(addr+i)^0x43);   //异或的数字根据情况修改
    }
}

static xor_setp3(){
    auto addr = 0x00414a84;   //这里填入要解密字节串的起始地址
    auto i = 0;
    for(i=0;addr+i<0x00414a84 + 347;i++)   //循环结束的条件为字节串的结束地址
    {
        PatchByte(addr+i,Byte(addr+i)^0x55);   //异或的数字根据情况修改
    }
}

static xor_setp4(){
    auto addr = 0x00414a30;   //这里填入要解密字节串的起始地址
    auto i = 0;
    for(i=0;addr+i<0x00414a30 + 83;i++)   //循环结束的条件为字节串的结束地址
    {
        PatchByte(addr+i,Byte(addr+i)^0x4D);   //异或的数字根据情况修改
    }
}

static main()
{
	xor_setp1();
}

实验分析

第一层

  1. 用IDA打开7-3的实验练习.exe,进入主函数如下图所示:
    在这里插入图片描述
  2. 主函数第一部分,主要的功能是按要求输入一串字符,并判断字符串长度是否等于28,如果不等于则输出"Try again……",等于28则入下一模块
lea     eax, [ebp+Str]   
push    eax
push    offset a100s    ; "%100s"
call    _scanf
add     esp, 8
lea     ecx, [ebp+Str]
push    ecx             ; Str
call    _strlen
add     esp, 4
mov     [ebp+var_4], eax
cmp     [ebp+var_4], 1Ch (28)
jz      short loc_40107F

在这里插入图片描述

  1. 接下来是判断字符串的最后一位(除\n)是否为7Dh("}"),如果不是则将eax置零并返回,之后跳转到最终的栈销毁操作。是则进入下一模块
    在这里插入图片描述
  2. 之后是for循环,条件为对byte_414C3C数组的前67个元素循环,在循环内部:
mov     edx, [ebp+var_70]
movsx   eax, byte_414C3C[edx]
xor     eax, 7Dh               //将byte_414C3C数组前67位元素每一位都异或7Dh(加密)
mov     ecx, [ebp+var_70]
mov     byte_414C3C[ecx], al        //异或结果覆盖原来的值
jmp     short loc_401095   

循环结束后:

loc_4010BC:
mov     dword ptr [ebp-6Ch], offset byte_414C3C //将byte_414C3C数组赋给dword ptr 					[ebp-6Ch]
mov     esi, esp
push    offset unk_414BE0       //将unk414BE0也就是下一层加密代码的地址压入栈
lea     edx, [ebp+Str]
push    edx
call    dword ptr [ebp-6Ch]
add     esp, 8
cmp     esi, esp
call    __chkesp
jmp     short loc_4010E1  

loc_4010E1:
xor     eax, eax     //返回结果eax=0
  1. 了解第一层结构后对第一层代码进行解密,双击byte_414C3C查看内容,推测为SMC加密代码,长度为67,起始地址为00414C3C,结束地址为00414C7F
    在这里插入图片描述
  2. 利用IDA执行idc解密脚本
#include <idc.idc>

static xor_setp1(){
    auto addr = 0x00414c3c;   //这里填入要解密字节串的起始地址
    auto i = 0;
    for(i=0;addr+i<0x00414C7F;i++)   //循环结束的条件为字节串的结束地址
    {
        PatchByte(addr+i,Byte(addr+i)^0x7D);   //异或的数字根据情况修改
    }
}
static main()
{
	xor_setp1();
}

点击File->Script file,打开解密脚本在这里插入图片描述
解密后byte_414C3C变为:
在这里插入图片描述
按快捷键C将字符串转换为汇编语言:
在这里插入图片描述
右键loc_414C3C,点击create function将汇编语言转换为函数,使其可以进行F5反汇编:
在这里插入图片描述
结果如下:
在这里插入图片描述
发现其逻辑为判断前五个字符是否为"flag{",不是则跳转到loc_414C7B,返回eax=0,是则进入loc_414C64,分析如下:

xor     byte ptr [ecx+edx], 43h      //将byte数组前90位逐位异或43h
inc     ecx							 //循环变量自增
cmp     ecx, 90               		 //循环条件:byte数组前90位
jl      short loc_414C64             // 即jump less指令,ecx小于90则跳转,do-while循环
add     eax, 5                
push    offset unk_414A84            //将偏移量unk_414A84压入栈,该地址对应的是第三层SMC函数地址
push    eax
call    edx
pop     ecx
pop     ecx

回到第一层main函数内给出的第二层自加密第二层代码:

loc_4010BC:
mov     dword ptr [ebp-6Ch], offset sub_414C3C
mov     esi, esp
push    offset unk_414BE0        //这里unk_414BE0嵌套在sub_414C3C,分析知为第二层的地址
lea     edx, [ebp+Str]
push    edx
call    dword ptr [ebp-6Ch]
add     esp, 8
cmp     esi, esp
call    __chkesp
jmp     short loc_4010E1

下面对unk_414BE0分析

第二层

  1. 双击unk_414BE0,如下:
    在这里插入图片描述
    根据代码格式推测为SMC,字符串起始位置的地址为00414BE0,结束地址为00414C3B。对unk_414BE0进行解密,使用idc脚本
#include <idc.idc>
static xor_setp2(){
    auto addr = 0x00414be0;   //这里填入要解密字节串的起始地址
    auto i = 0;
    for(i=0;addr+i<0x00414C3A;i++)   //循环结束的条件为字节串的结束地址
    {
        PatchByte(addr+i,Byte(addr+i)^0x43);   //异或的数字根据情况修改
    }
}
static main()
{
	xor_setp2();
}

解密后:
在这里插入图片描述
按快捷键C转换为汇编语言:
在这里插入图片描述
右键create function得汇编函数,进行分析:

.data:00414BE0 sub_414BE0      proc near               ; DATA XREF: _main_0+B5↑o
.data:00414BE0
.data:00414BE0 var_8           = dword ptr -8
.data:00414BE0 var_4           = byte ptr -4
.data:00414BE0 arg_0           = dword ptr  8
.data:00414BE0 arg_4           = dword ptr  0Ch
.data:00414BE0
.data:00414BE0                 push    ebp
.data:00414BE1                 mov     ebp, esp
.data:00414BE3                 push    ecx
.data:00414BE4                 push    ecx
.data:00414BE5                 push    ebx
.data:00414BE6                 mov     ebx, [ebp+arg_0]
.data:00414BE9                 lea     eax, [ebp+var_8]
.data:00414BEC                 push    esi
.data:00414BED                 push    edi
.data:00414BEE                 xor     edx, edx           //edx变量置0
.data:00414BF0                 mov     [ebp+var_8], 93A9A498h  //[ebp+var_8]设 
.data:00414BF7                 mov     edi, ebx     			//为-1817598824
.data:00414BF9                 mov     [ebp+var_4], dl
.data:00414BFC                 mov     esi, edx
.data:00414BFE                 sub     edi, eax     //edi减去eax结果存入edi   
.data:00414C00
.data:00414C00 loc_414C00:                             ; CODE XREF: sub_414BE0+32↓j
.data:00414C00                 lea     ecx, [ebp+var_8]
.data:00414C03                 add     ecx, esi   		//将ecx,esi相加
.data:00414C05                 mov     al, [edi+ecx] //将edi和ecx对应的数赋给al寄存器
.data:00414C08                 xor     al, 0CCh      //al 异或0CCh
.data:00414C0A                 cmp     al, [ecx]     //判断al的值是否和
.data:00414C0C                 jnz     short loc_414C31  //这里为while循环的标志,如果不相等跳到loc_414C31进行栈销毁,否则进入循环内部
.data:00414C0E                 inc     esi           //esi自增
.data:00414C0F                 cmp     esi, 4        //判断esi是否和4相等
.data:00414C12                 jl      short loc_414C00   //如果esi小于4则进行下一层,否则进入if语句内部
.data:00414C14                 mov     ecx, [ebp+arg_4]
.data:00414C17
.data:00414C17 loc_414C17:                             ; CODE XREF: sub_414BE0+42↓j
.data:00414C17                 xor     byte ptr [edx+ecx], 55h  //将edx和ecx相加的结果与55h异或
.data:00414C1B                 inc     edx     //edx自增
.data:00414C1C                 cmp     edx, 15Bh        //循环变量edx和15BH比较
.data:00414C22                 jl      short loc_414C17  //do-while循环入口,如果edx小于15BH则进入循环,跳转到loc_414C17,否则跳出循环
.data:00414C24                 lea     eax, [ebx+4]   //ebx参数和4相加存入eax
.data:00414C27                 push    offset unk_414A30  //将地址unk_414A30压入栈传入下面的ecx
.data:00414C2C                 push    eax     
.data:00414C2D                 call    ecx      //调用ecx函数
.data:00414C2F                 pop     ecx
.data:00414C30                 pop     ecx
.data:00414C31
.data:00414C31 loc_414C31:                             ; CODE XREF: sub_414BE0+2C↑j
.data:00414C31                 pop     edi
.data:00414C32                 pop     esi
.data:00414C33                 xor     eax, eax
.data:00414C35                 pop     ebx
.data:00414C36                 mov     esp, ebp
.data:00414C38                 pop     ebp
.data:00414C39                 retn
.data:00414C39 sub_414BE0      endp
.data:00414C39

根据分析可知while代码执行的条件为: *(a1+v3)^0xCC == (&v5+v3), 也就是输入的字符异或0xCC对应与v5中的数0x93A9A498相等,求得字符为_ehT, 由于与输入的字符顺序相反,故输入的第6-9个字符为The_

回到第二层sub_414C3C函数,对于传入的地址unk_414A84进行分析

第三层

  1. 双击unk_414A84
    在这里插入图片描述
  2. 分析代码逻辑为SMC自加密,同理使用idc脚本:
#include <idc.idc>

static xor_setp3(){
    auto addr = 0x00414a84;   //这里填入要解密字节串的起始地址
    auto i = 0;
    for(i=0;addr+i<0x00414a84 + 347;i++)   //循环结束的条件为字节串的结束地址
    {
        PatchByte(addr+i,Byte(addr+i)^0x55);   //异或的数字根据情况修改
    }
}
static main()
{
	xor_setp3();
}

解密结果为:
在这里插入图片描述
按快捷键C转换为汇编语言:
在这里插入图片描述
右键点击create function转换为函数:
在这里插入图片描述
发现出现很多诸如"A-Z",“a-z”,“0-9"以及结尾出现的”="推测进行的是base64加密,分析汇编语言结构:前几个loc函数都有cmp和jle等循环标志,继续分析,注意到

.data:00414AD2                 mov     dword ptr [ebp+var_10], 'hVmc'
.data:00414AD9                 mov     dword ptr [ebp+var_10+4], '0NEb'
.data:00414AE0                 mov     dword ptr [ebp+var_10+8], '=8lR'
.data:00414AE7                 stosd
.data:00414AE8                 mov     [ebp+var_10+0Ch], cl
.data:00414AEB                 stosd
.data:00414AEC                 mov     edi, ecx

这里传入了固定字符串"cmVhbEN0Rl8="推测为flag的第10到17位,接下来的几个loc函数为base64的右移运算部分。在函数的末尾,注意到
在这里插入图片描述
dl和固定字符串在while循环内进行了相等判断,同时可以用OD进行动态运行该程序到第三个函数随便输入的字符串加密后的结果仍为固定字符串,因此对字符串base64解密得:realCtF_,如果比较正确后则对sub_414A30函数解密并编译,即该程序的第三层嵌套:
回到第二层给出的地址 unk_414A30,进入下一层分析

第四层

  1. 双击unk_414A30查看
    在这里插入图片描述

同理分析其为SMC自加密,使用idc脚本解密:

#include <idc.idc>

static xor_setp4(){
    auto addr = 0x00414a30;   //这里填入要解密字节串的起始地址
    auto i = 0;
    for(i=0;addr+i<0x00414a30 + 83;i++)   //循环结束的条件为字节串的结束地址
    {
        PatchByte(addr+i,Byte(addr+i)^0x4D);   //异或的数字根据情况修改
    }
}
static main()
{
	xor_setp4();
}

解密结果:
在这里插入图片描述

按快捷键C转换为汇编代码:
在这里插入图片描述
右键create function生成汇编函数:
在这里插入图片描述
分析逻辑,注意到函数压入了6FF22h,68344360h,7574766Bh,转换为字符串为"kvtu`C4h\"o",在loc_414A55函数中,edx自增后,将byte ptr [ebp+edx+var_C]和bl(之前存入得三串字符串)判断是否相等,并且如果不相等则跳转到本身,分析为while循环,在循环内部,edi减去了esi,而esi为参数地址,edi为字符串,而在loc_414A68中又进行了dec ecx即ecx自减,可知逻辑为将参数地址所有的字符减1和字符串比较,所以输入的字符串应该为"just_B3g!n"。

总结

综上所述,flag为 :flag{The_realCtF_just_B3g!n}

附件

链接:https://pan.baidu.com/s/1WsgS9GHjbZOjjS6YuJiYhQ
提取码:j2km

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Y1seco

我们都在慢慢进步

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值