首先我们用FileAnalysisv判断文件可能的格式,可知极有可能是win32下的Exe文件,于是我们加上拓展名.exe,于是可以正常打开这个程序,如下:

然后把它扔进ida进行反汇编,根据伪代码的特性可以大致断定是一个C++写出的程序,其中main函数的伪代码如下
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [esp+1Ch] [ebp-48h]
int v5; // [esp+20h] [ebp-44h]
char v6[32]; // [esp+24h] [ebp-40h]
char v7; // [esp+44h] [ebp-20h]
int v8; // [esp+45h] [ebp-1Fh]
__int16 v9; // [esp+49h] [ebp-1Bh]
char v10; // [esp+4Bh] [ebp-19h]
int k; // [esp+4Ch] [ebp-18h]
int j; // [esp+50h] [ebp-14h]
int i; // [esp+54h] [ebp-10h]
int v14; // [esp+58h] [ebp-Ch]
int v15; // [esp+5Ch] [ebp-8h]
__main();
v8 = 0;
v9 = 0;
v10 = 0;
memset(v6, 0, sizeof(v6));
v7 = 0;
v5 = 0;
v4 = 0;
v15 = 0;
v14 = 0;
printf("Please input your luck string:");
scanf("%s", &v8);
if ( strlen((const char *)&v8) != 6 )//限制输入的luckstring长度为6
return 0;
for ( i = 0; i <= 5; ++i )
{
if ( *((_BYTE *)&v8 + i) <= 96 || *((_BYTE *)&v8 + i) > 122 )
return 0;
}//限制luckstring全部由小写字母组成
getMD5((char *)&v8, v6);//对luckstring进行md5加密存进V6数组
for ( j = 0; j <= 31; ++j )//可初步断定加密后数组长度为32位
{
if ( v6[j] == 48 )//v15记录为0的位置个数
{//v14记录所有为0的位置编号的和
++v15;
v14 += j;
}
}
if ( 10 * v15 + v14 == 403 )//表达式为403的时候进行加密和decode函数
{
for ( k = 0; k <= 3; ++k )
{
*((_BYTE *)&v5 + k) = v6[k];
*((_BYTE *)&v4 + k) = v6[k + 28];
}
decode((unsigned __int8 *)&v4);
}
check((unsigned __int8 *)&v5);
return 0;
}
虽然我们不知道flag是什么时候出现的,但是decode函数是编码函数这一点没有问题。所以我们首先探索什么样的luck string满足if表达式中的条件。
首要的任务是md5加密。这里有两种方法,第一种是点getMD5函数然后用C++逐层分析出来加密源代码,然后分6层枚举luckstring。但是由于本人代码能力较弱,还原出来的getMD5函数BUG太多,所以我选择了用Java里面自带的MD5加密方法:
package md5;
import java.math.BigInteger;
import java.security.MessageDigest;
public class AppMD5Util {
public static String MD5(String s) {
char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
try {
byte[] btInput = s.getBytes();
MessageDigest mdInst = MessageDigest.getInstance("MD5");
mdInst.update(btInput);
byte[] md = mdInst.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
for(int i1=97;i1<=122;i1++)
for(int i2=97;i2<=122;i2++)
for(int i3=97;i3<=122;i3++)
for(int i4=97;i4<=122;i4++)
for(int i5=97;i5<=122;i5++)
for(int i6=97;i6<=122;i6++) {
char a=(char)i1,b=(char)i2,c=(char)i3;
char d=(char)i4,e=(char)i5,f=(char)i6;
String temp=a+""+b+""+c+""+d+""+e+""+f;
String code=MD5(temp);
char[] Code=code.toCharArray();
int cnt2=0,cnt1=0;
for(int i=0;i<=31;i++)
if(Code[i]==48) {
cnt2++;cnt1+=i;
}
System.out.println(temp);
if(10*cnt2+cnt1==403) {
System.out.println(temp);
System.exit(0);
}
}
/*String temp="ozulmt";
System.out.println(MD5(temp));*/
}
}
等待的时间可能比较长,但是跑出来"ozulmt"还是没问题的,这就是我们需要的luckstring。在输入之后,程序又提示我们输入flag。
我们首先打印出md5加密后的luckstring(被程序存在v6中):0ec448d42dbf0000c020c0000048010e
接着我们把main函数里面的v4,v5数组计算出来,这个很容易知道他们分别是v6开头4个元素和结尾4个元素
v4="010e",v5="0ec4"
然后我们自然会想到点进后面的decode和check函数里面,但是进入decode之后我们发现它使用了check函数的指针,点进check函数之后发现竟然只有一个return。我们再来分析decode函数
// write access to const memory has been detected, the output may be wrong!
signed int __cdecl decode(unsigned __int8 *a1)
{
signed int result; // eax
signed int j; // [esp+24h] [ebp-14h]
signed int i; // [esp+28h] [ebp-10h]
unsigned int v4; // [esp+2Ch] [ebp-Ch]
v4 = 0;
for ( i = 0; i <= 3; ++i )
v4 += a1[i];
srand(v4);//种子是一定的,产生随机数的顺序是一定的,说明check函数在以后的进程中可以被还原
*(_BYTE *)check ^= 0x96u;
for ( j = 1; ; ++j )
{
result = j;
if ( j >= 305 )
break;
*((_BYTE *)check + j) ^= rand();
}
return result;
}
我们发现这个decode函数居然是给check函数还原用的……不过总归找到了方向,我们在x32dbg中动态调试,跟到decode函数内部,并且密切关注Check函数地址。最后我们终于能够进入check函数的汇编代码
0040262 | 55 | push ebp |
0040262 | 89 E5 | mov ebp,esp |
0040262 | 57 | push edi |
0040262 | 53 | push ebx |
0040262 | 83 C4 80 | add esp,FFFFFF80 |
0040262 | C7 45 F4 00 00 00 00 | mov dword ptr ss:[ebp-C],0 |
0040263 | C7 45 F0 00 00 00 00 | mov dword ptr ss:[ebp-10],0 |
0040263 | 83 7D F0 03 | cmp dword ptr ss:[ebp-10],3 |
0040264 | 7F 17 | jg what.402659 |
0040264 | 8B 55 F0 | mov edx,dword ptr ss:[ebp-10] |
0040264 | 8B 45 08 | mov eax,dword ptr ss:[ebp+8] |
0040264 | 01 D0 | add eax,edx |
0040264 | 0F B6 00 | movzx eax,byte ptr ds:[eax] |
0040264 | 0F B6 C0 | movzx eax,al |
0040265 | 01 45 F4 | add dword ptr ss:[ebp-C],eax |
0040265 | 83 45 F0 01 | add dword ptr ss:[ebp-10],1 |
0040265 | EB E3 | jmp what.40263C |
0040265 | 8B 45 F4 | mov eax,dword ptr ss:[ebp-C] |
0040265 | 89 04 24 | mov dword ptr ss:[esp],eax | [esp]:0ec40ec448d42dbf0000c020c0000048010e
0040265 | E8 C6 FD FF FF | call what.40242A |
0040266 | 8D 45 95 | lea eax,dword ptr ss:[ebp-6B] |
0040266 | B9 21 00 00 00 | mov ecx,21 |
0040266 | BB 00 00 00 00 | mov ebx,0 |
0040267 | 89 18 | mov dword ptr ds:[eax],ebx |
0040267 | 89 5C 08 FC | mov dword ptr ds:[eax+ecx-4],ebx |
0040267 | 8D 50 04 | lea edx,dword ptr ds:[eax+4] |
0040267 | 83 E2 FC | and edx,FFFFFFFC |
0040267 | 29 D0 | sub eax,edx |
0040267 | 01 C1 | add ecx,eax |
0040268 | 83 E1 FC | and ecx,FFFFFFFC |
0040268 | C1 E9 02 | shr ecx,2 |
0040268 | 89 D7 | mov edi,edx |
0040268 | 89 D8 | mov eax,ebx |
0040268 | F3 AB | rep stosd dword ptr es:[edi],eax |
0040268 | C7 04 24 01 00 00 00 | mov dword ptr ss:[esp],1 | [esp]:0ec40ec448d42dbf0000c020c0000048010e
0040269 | E8 32 FD FF FF | call what.4023CB |
0040269 | 8D 45 B6 | lea eax,dword ptr ss:[ebp-4A] |
0040269 | 89 04 24 | mov dword ptr ss:[esp],eax | [esp]:0ec40ec448d42dbf0000c020c0000048010e
0040269 | E8 AD FD FF FF | call what.402451 |
004026A | 8D 45 B6 | lea eax,dword ptr ss:[ebp-4A] |
004026A | 89 04 24 | mov dword ptr ss:[esp],eax | [esp]:0ec40ec448d42dbf0000c020c0000048010e
004026A | E8 BE FD FF FF | call what.40246D |
004026A | C7 45 EC 00 00 00 00 | mov dword ptr ss:[ebp-14],0 |
004026B | 83 7D EC 1F | cmp dword ptr ss:[ebp-14],1F |
004026B | 7F 25 | jg what.4026E1 |
004026B | C7 04 24 10 00 00 00 | mov dword ptr ss:[esp],10 | [esp]:0ec40ec448d42dbf0000c020c0000048010e
004026C | E8 76 FD FF FF | call what.40243E |
004026C | 0F B6 80 60 60 40 00 | movzx eax,byte ptr ds:[eax+406060] | eax+406060:"0123456789abcdef"
004026C | 89 C1 | mov ecx,eax |
004026D | 8D 55 95 | lea edx,dword ptr ss:[ebp-6B] |
004026D | 8B 45 EC | mov eax,dword ptr ss:[ebp-14] |
004026D | 01 D0 | add eax,edx |
004026D | 88 08 | mov byte ptr ds:[eax],cl |
004026D | 83 45 EC 01 | add dword ptr ss:[ebp-14],1 |
004026D | EB D5 | jmp what.4026B6 |
004026E | C7 45 F4 00 00 00 00 | mov dword ptr ss:[ebp-C],0 |
004026E | C7 45 E8 00 00 00 00 | mov dword ptr ss:[ebp-18],0 |
004026E | 8D 45 B6 | lea eax,dword ptr ss:[ebp-4A] |
004026F | 89 04 24 | mov dword ptr ss:[esp],eax | [esp]:0ec40ec448d42dbf0000c020c0000048010e
004026F | E8 BE FC FF FF | call what.4023B8 |
004026F | 3B 45 E8 | cmp eax,dword ptr ss:[ebp-18] |
004026F | 0F 9F C0 | setg al |
0040270 | 84 C0 | test al,al |
0040270 | 74 2A | je what.40272E |
0040270 | 8D 55 B6 | lea edx,dword ptr ss:[ebp-4A] |
0040270 | 8B 45 E8 | mov eax,dword ptr ss:[ebp-18] |
0040270 | 01 D0 | add eax,edx |
0040270 | 0F B6 10 | movzx edx,byte ptr ds:[eax] |
0040270 | 8D 4D 95 | lea ecx,dword ptr ss:[ebp-6B] |
0040271 | 8B 45 E8 | mov eax,dword ptr ss:[ebp-18] |
0040271 | 01 C8 | add eax,ecx |
0040271 | 0F B6 00 | movzx eax,byte ptr ds:[eax] |
0040271 | 38 C2 | cmp dl,al |
0040271 | 75 06 | jne what.402724 |
0040271 | 83 45 F4 01 | add dword ptr ss:[ebp-C],1 |
0040272 | EB 04 | jmp what.402728 |
0040272 | 83 45 F4 64 | add dword ptr ss:[ebp-C],64 |
0040272 | 83 45 E8 01 | add dword ptr ss:[ebp-18],1 |
0040272 | EB C1 | jmp what.4026EF |
0040272 | 83 7D F4 20 | cmp dword ptr ss:[ebp-C],20 |
0040273 | 75 09 | jne what.40273D |
0040273 | C7 45 F4 02 00 00 00 | mov dword ptr ss:[ebp-C],2 |
0040273 | EB 07 | jmp what.402744 |
0040273 | C7 45 F4 03 00 00 00 | mov dword ptr ss:[ebp-C],3 |
0040274 | 8B 45 F4 | mov eax,dword ptr ss:[ebp-C] |
0040274 | 89 04 24 | mov dword ptr ss:[esp],eax | [esp]:0ec40ec448d42dbf0000c020c0000048010e
0040274 | E8 7C FC FF FF | call what.4023CB |
0040274 | 90 | nop |
0040275 | 83 EC 80 | sub esp,FFFFFF80 |
0040275 | 5B | pop ebx |
0040275 | 5F | pop edi |
0040275 | 5D | pop ebp |
0040275 | C3 | ret |
这段代码,确实特别恶心……但是这也确实是最后一个我们需要攻克的难关。这里我借鉴一下吾爱破解的一筐萝卜用户的check函数伪代码:

我们看到check函数内部有几个新的函数,不过这些函数都是没有加密的,在ida里可以直接进入这些函数(即便check函数没有恢复)。printfs函数根据参数的值输出不同的字符串提示内容,checkht函数是检查我们输入的flag的格式是否正确……这些都是小问题了(对比前面的过程)
最后大概就可以愉快的拿到flag辣!

总之,CTF比赛和OI比赛区别还是很大的,但是CTF比赛有的时候也需要OI功底。十分庆幸我选择了RE方向,还算不错的算法能力给我带来了很多的好处,但是知识面单一的问题也很限制我的发展。
3243

被折叠的 条评论
为什么被折叠?



