从这道题中学到了很多东西--------
我当时和一个朋友抱怨 有没有有难度的题 而且还有wp的 因为 没有wp 做了好多天都没有结果 还没有答案是一件非常难受的事
本来这个题 我想用ida的idc 或者 python来解题的 但是 后来发现。。。。。 不会
很尴尬 还拿了书 结果 看是能看懂 但是根本就没有办法 怎么说 让问题简单化 用python 我百度了一下 发现还是要调用c语言的api函数 (那我不如直接用c语言的) 但是这又背离了我的初衷 所以 我就直接粘贴复制简单暴力。。。
先说说这道题 一开始这道题并没有显示出来是exe文件 我拖入llinux 然后发现竟然是个32位 PE文件???? 然后后缀改成exe 然后直接就能运行了 然后这道题 看起来也没有那么难
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 ) // 长度为6
return 0;
for ( i = 0; i <= 5; ++i )
{
if ( *((_BYTE *)&v8 + i) <= 96 || *((_BYTE *)&v8 + i) > 122 )// a~z
return 0;
}
getMD5((char *)&v8, v6); // md5加密
for ( j = 0; j <= 31; ++j )
{
if ( v6[j] == 48 )
{
++v15;
v14 += j;
}
}
if ( 10 * v15 + v14 == 403 ) // 这里就可以 暴力求我们输入的值
{
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;
}
看到这我的想法就是直接爆破输入就ok了 6个for循环加上 a~z的数据范围 然后这是我爆破的脚本
import hashlib
import string
m=hashlib.md5()
def encrypt_md5(str):
md = hashlib.md5() # 创建md5对象
md.update(str.encode(encoding='utf-8')) # 这里必须用encode()函数对字符串进行编码,不然会报 TypeError: Unicode-objects must be encoded before hashing
return md.hexdigest() # 加密
sign=''
for i in range(97,123):
for j in range(97,123):
for k in range(97,123):
for l in range(97,123):
for s in range(97,123):
for a in range(97,123):
g=0
gg=0
sign=''
ss=''
sign=chr(i)+chr(j)+chr(k)+chr(l)+chr(s)+chr(a)
ss=encrypt_md5(sign)
for xx in range(0,32):
if ss[xx]=="0":
g=g+1
gg=gg+xx
if gg+g*10==403:
print (sign)
break
然后这是我爆破的密码
爆破的字符串:ozulmt 然后我们 我们再往下看
看着后面 它传入的是我们后面爆破的字符串 md5加密后的 前四位 和后四位 那我们再写出脚本
import hashlib
import string
m=hashlib.md5()
def encrypt_md5(str):
md = hashlib.md5() # 创建md5对象
md.update(str.encode(encoding='utf-8')) # 这里必须用encode()函数对字符串进行编码,不然会报 TypeError: Unicode-objects must be encoded before hashing
return md.hexdigest() # 加密
string_s=encrypt_md5("ozulmt")
s=[""]*4
ss=[""]*4
for x in range(4):
s[x]=string_s[x]
ss[x]=string_s[x+28]
print (s)
print (ss)
啊咧? check 是个函数 异或函数? 然后点开check 发现函数f5不行 也就是说这个函数 是被异或加密的 异或的字节 也很好能看出来 就是305 这里就是上面我说的那个 用脚本可以直接异或。。可惜我不怎么会 然后还看了很多书 也请教了很多学长 还是感觉不怎么会 然后我就直接 再od里面查找我们 地址是402626 然后 305的字节是
5589E5575383C480C745F400000000C745F000000000837DF0037F178B55F08B450801D00FB6000FB6C00145F48345F001EBE38B45F4890424E8C6FDFFFF8D4595B921000000BB000000008918895C08FC8D500483E2FC29D001C183E1FCC1E90289D789D8F3ABC7042401000000E832FDFFFF8D45B6890424E8ADFDFFFF8D45B6890424E8BEFDFFFFC745EC00000000837DEC1F7F25C7042410000000E876FDFFFF0FB6806060400089C18D55958B45EC01D088088345EC01EBD5C745F400000000C745E8000000008D45B6890424E8BEFCFFFF3B45E80F9FC084C0742A8D55B68B45E801D00FB6108D4D958B45E801C80FB60038C275068345F401EB048345F4648345E801EBC1837DF4207509C745F402000000EB07C745F4030000008B45F4890424E87CFCFFFF9083EC805B5F5DC3
然后我们就很简单的能够得到check
为什么printfs 的2是正解 我们看一下printfs
然后 我在上面发现了一个检查我们输入flag值的地方 我们点进去看看
这里应该还是解释的挺清楚的 也就是说 flag的格式 是flag{xxx-xxx-xxx-xxx-xxx} 然后 到后面 输入的值变成了 xxxxxxxxxxxxxx 去掉了 - 和flag { } 然后
然后我们发现种子就是我们上面得出来的数组和 然后我们可以写个程序
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;
char s[]={"0123456789abcdef"};
char ss[]={"0ec4"};
char ans[32];
int seed;
int main()
{
int sum=0;
for(int i=0;i<4;i++)
seed+=ss[i];
srand(seed);
for(int i=0;i<32;i++)
{
ans[i]=s[rand()%16];
}
printf("flag{");
for(int i=0;i<36;i++)
{
if(i==8||i==13||i==18||i==23)
{
printf("%c",45);
sum++;
continue;
}
printf("%c",ans[i-sum]);
}
printf("}");
return 0;
}