目录
FCTF
FlowerDance
花指令:一种专门用来迷惑反编译器的指令片段(不影响程序,但会使反汇编器结果出现问题)
经典的花指令有:jmp,call,ret等
详细原理的链接:恶意代码分析实战 第十五章 对抗反汇编 - 简书
解决办法:
- 直接分析异常地址处的指令,分辨花指令和有用的数据
- 用nop(0x90)填充垃圾数据
具体操作:
- 先按U识别为数据
- Edit -> Patch program -> change byte
- 将E8修改为90(nop指令)
- 再按C转为nop指令
剩余的如法炮制,全部的花指令nop之后
按P键重新反编译(要点到main那里才行)
然后按空格键回到方块那里(不知道叫什么),再按F5进行反汇编即可
分析伪代码:
可以知道加密操作那么写出对应解密代码即可
注意解密代码编写时key[i % 8]要对应着加密过程的,不能有误
解密代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
int main(){
char v7[8];
strcpy(v7, "JunkCode");
char data_1[28];
memcpy(data_1, "FkbXXL", 6);
data_1[6] = 12;
memcpy(&data_1[7], "^$iP", 4);
data_1[11] = 127;
data_1[12] = 100;
data_1[13] = 33;
data_1[14] = 56;
data_1[15] = 112;
data_1[16] = 82;
data_1[17] = 47;
data_1[18] = 62;
data_1[19] = 29;
data_1[20] = 100;
data_1[21] = 35;
data_1[22] = 125;
data_1[23] = 116;
data_1[24] = 74;
data_1[25] = 96;
data_1[26] = 8;
data_1[27] = 74;
int j=26;
for ( int i = 0; i<27; i++){
data_1[i+1] ^= v7[j % 8] ^ data_1[i];//关键
j--;
}
puts(data_1);
return 0;
}
得到答案:FCTF{S0-be@ut1fUl-f10weRs}
EzSMC
SMC:自修改代码(Self-Modified Code),是一种特殊的代码技术(在运行时修改自身代码,从而使得程序实际行为与反汇编结果不符,同时修改前的代码段数据也肯非合法指令,从而无法被反汇编器识别)
换句话说,SMC是一种额外的加密技术,在不运行的时候,代码里会加密导致反汇编不出来结果,但是在运行的时候会进行解密然后得到结果
通常的两种破解方式:
- 根据静态分析结果(分析逻辑)直接修改程序中的二进制文件(阿巴阿巴阿巴,不太懂)
- 在动态调试时将解密后的程序从内存中dump下来(就是动态调试的时候可以直接得到解密后的程序)
这题主要考察动态调试(具体调试过程等之后补上,咱就是说回来补上了,主打不落下一点)
SMC基本操作:
- 获取函数首地址
- 取消目标地址处读写保护属性
- 修改代码(这里是异或操作)
- 恢复目标地址处读写保护属性
调试过程:
1.首先正常操作(不细讲了),打开文件并进行反汇编即可
2.下断点,选择合适的调试器(这里使用windows 调试),开始调试
3.这是进入调试之后的页面,然后跟进func()函数
4.跟进后,从func()函数的开头一直到main()函数的前面锁定(就是选中func函数那一块),按U键取消加密(感觉像)
5.再选中func函数那一块按C键识别为代码(有时候可能会有弹窗,点击force,强制执行即可)
6.再选中func函数,按P键重新识别函数,再按F5反汇编即可得到解密后的程序
一些快捷键的使用:
按G键:可以进行跳转到函数地址(可以提前记录地址然后跳转,很方便)
Alt+L:可以固定选中,不用担心点一下选中区域就被取消了(也很好用)
shift+e:快速提取数据
这里放出调试完成后的代码:
可以看出flag和一堆数据进行了异或操作,最后的密文是data(这个数据需要跟进去看并提取出来),那么相应的写出解密代码即可。
解密代码:
#include <stdio.h>
#include <string.h>
#include <math.h>
int main(){
char Str[] =
{
29, 24, 15, 29, 32, 2, 107, 46, 118, 27,
41, 62, 118, 45, 104, 41, 34, 118, 48, 21,
52, 44, 118, 40, 54, 56, 118, 58, 51, 63,
118, 35, 107, 41, 38
};
for ( int i = 0; i <= 34; ++i )
Str[i] ^= 0x31u;
for ( int j = 0; j <= 34; ++j )
Str[j] ^= 7u;
for ( int k = 0; k <= 34; ++k )
Str[k] ^= 5u;
for ( int m = 0; m <= 34; ++m )
Str[m] ^= 0xDu;
for ( int n = 0; n <= 34; ++n )
Str[n] ^= 0x67u;
for ( int ii = 0; ii <= 34; ++ii )
Str[ii] ^= 0x48u;
for ( int jj = 0; jj <= 34; ++jj )
Str[jj] ^= 0x53u;
for ( int kk = 0; kk <= 34; ++kk )
Str[kk] ^= 0x50u;
for ( int mm = 0; mm <= 34; ++mm )
Str[mm] ^= 0x35u;
for ( int nn = 0; nn <= 34; ++nn )
Str[nn] ^= 0x40u;
for ( int i1 = 0; i1 <= 34; ++i1 )
Str[i1] ^= 0x44u;
for ( int i2 = 0; i2 <= 34; ++i2 )
Str[i2] ^= 0x2Bu;
for ( int i3 = 0; i3 <= 34; ++i3 )
Str[i3] ^= 0x2Eu;
for ( int i4 = 0; i4 <= 34; ++i4 )
Str[i4] ^= 0x57u;
for ( int i5 = 0; i5 <= 34; ++i5 )
Str[i5] ^= 0x5Fu;
for ( int i6 = 0; i6 <= 34; ++i6 )
Str[i6] ^= 0x2Cu;
for ( int i7 = 0; i7 <= 34; ++i7 )
Str[i7] ^= 0x65u;
for ( int i8 = 0; i8 <= 34; ++i8 )
Str[i8] ^= 0x2Fu;
for ( int i9 = 0; i9 <= 34; ++i9 )
Str[i9] ^= 1u;
for ( int i10 = 0; i10 <= 34; ++i10 )
Str[i10] ^= 0xDu;
for ( int i11 = 0; i11 <= 34; ++i11 )
Str[i11] ^= 0x1Eu;
for ( int i12 = 0; i12 <= 34; ++i12 )
Str[i12] ^= 0x22u;
for (int i13 = 0; i13 <= 34; ++i13 )
Str[i13] ^= 0x18u;
for ( int i14 = 0; i14 <= 34; ++i14 )
Str[i14] ^= 0x2Du;
for ( int i15 = 0; i15 <= 34; ++i15 )
Str[i15] ^= 0x5Fu;
for ( int i16 = 0; i16 <= 34; ++i16 )
Str[i16] ^= 0x5Fu;
for ( int i17 = 0; i17 <= 34; ++i17 )
Str[i17] ^= 0x15u;
for ( int i18 = 0; i18 <= 34; ++i18 )
Str[i18] ^= 0x45u;
for ( int i19 = 0; i19 <= 34; ++i19 )
Str[i19] ^= 0x53u;
for ( int i20 = 0; i20 <= 34; ++i20 )
Str[i20] ^= 0x5Du;
for (int i21 = 0; i21 <= 34; ++i21 )
Str[i21] ^= 0x6Cu;
for ( int i22 = 0; i22 <= 34; ++i22 )
Str[i22] ^= 0x24u;
for ( int i = 0; i <= 34; ++i)
printf("%c",Str[i]);
return 0;
}
得到答案:FCTF{Y0u-@re-v3ry-kNow-smc-ahd-x0r}
BUU
reverse3
1.首先正常操作(查壳,反汇编出伪代码)
2.对伪代码进行分析(部分的变量名我进行更改了,更好理解)
跟进sub_4110BE加密操作:很复杂的感觉(看了网上的wp才知道这是Base64的加密过程,真的看不懂啊)
跟进Str2:可以得到密文
那么现在就能够知道主要的加密过程:flag--->Base64加密---->然后进行了一个加法操作---->得到密文
那么现在进行反操作即可,Base64解密直接网上找解密器就行
解密代码:
#include <stdio.h>
#include <string.h>
int main(){
char Str2[]="e3nifIH9b_C@n@dH";
for ( int j = 0; j < strlen(Str2); ++j )
Str2[j] -= j;
puts(Str2);
return 0;
}
得到:e2lfbDB2ZV95b3V9
然后Base64解密得到:{i_l0ve_you}
不一样的flag
很明显这是一道迷宫问题
解决问题三要素:地图,起点和终点位置,上下左右的操作符
打开文件(常规操作):
由地图的限制条件可以得到迷宫共有5行(行值一开始是0),那么可以得到地图是5*5
再结合代码可以知道起点在(0,0)处,终点在“#”
由伪代码可得:
移动操作符:1-上,2-下,3-左,4-右
地图:
路线就可以直接手动画出:(只是对于简单的迷宫题,复杂的可以套脚本)
那么可以得到答案:flag{222441144222}