吾爱破解,初来报道!(可能有些地方分析得不太正确,还望多宽(容)待!)
这道题我做了两天,卡死在了写脚本上了,不断修改脚本,过程中学到了挺多!
<!-- more-->
寻找关键:
记事本打开发现是elf文件,然后在ubuntu中运行,提示让我们输入flag,随便输入,回复我们:wrong 于是拖入IDA F12
LOAD:0000000000400238 0000001C C /lib64/ld-linux-x86-64.so.2
LOAD:0000000000400349 0000000A C libc.so.6
LOAD:0000000000400353 00000005 C puts
LOAD:0000000000400358 00000007 C strlen
LOAD:000000000040035F 00000006 C scanf
LOAD:0000000000400365 00000012 C __libc_start_main
LOAD:0000000000400377 0000000F C __gmon_start__
LOAD:0000000000400386 0000000C C GLIBC_2.2.5
.rodata:0000000000400848 0000000E C [WxyVM 0.0.1]
.rodata:0000000000400856 00000011 C input your flag:
.rodata:000000000040086A 00000008 C correct
.rodata:0000000000400872 00000006 C wrong
.eh_frame:000000000040091F 00000006 C ;*3$\"
找到input your flag 鼠标双击它 来到它的位置,然后按X查看哪里引用它了
然后就来到了main函数了 F5 看下主函数的反编译
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
char v4; // [rsp+Bh] [rbp-5h]
signed int i; // [rsp+Ch] [rbp-4h]
puts("[WxyVM 0.0.1]");
puts("input your flag:");
scanf("%s", &byte_604B80); // 输入字符串存在 604B80处
v4 = 1;
sub_4005B6();
if ( strlen(&byte_604B80) != 24 ) // 604B80处的字符串长度为24
v4 = 0;
for ( i = 0; i <= 23; ++i )
{
if ( *(&byte_604B80 + i) != dword_601060[i] )// 604B80处的每个字节 与601060处每个双字的最后两位(即字节)要相等
v4 = 0;
}
if ( v4 )
puts("correct");
else
puts("wrong");
return 0LL;
}
这里注意下601060[i]存的是24个双字类型的数据,所以与604B80i做比较时 只需比较的是601060处每个双字的最后两位(即字节)<br>
我们再看下 sub_4005B6()函数做了什么
__int64 sub_4005B6()
{
unsigned int v0; // ST04_4
__int64 result; // rax
signed int i; // [rsp+0h] [rbp-10h]
char v3; // [rsp+8h] [rbp-8h]
for ( i = 0; i <= 14999; i += 3 ) // 6010C0地址存放着 15000字节大小的 16进制数 3个为1组
{
v0 = byte_6010C0[i]; // v0=每组的第一个 16进制数
v3 = byte_6010C0[i + 2]; // v3 为每组的第三个 16进制数
result = v0; // result赋初值 每组的的第一个16进制数
switch ( v0 ) // 根据每组的第一个 16进制数 决定接下来进行什么操作(算法)
{
case 1u:
result = byte_6010C0[i + 1]; // result = 每组的第二个 16进制数
*(&byte_604B80 + result) += v3; // 604B80是我们输入字符串存放的地址(指针)
// 所以这里就相当与 604B80[0+result]=604B80[0+result]+v3
break;
case 2u: // 同理 604B80[0+result]=604B80[0+result]-v3
result = byte_6010C0[i + 1];
*(&byte_604B80 + result) -= v3;
break;
case 3u: // 同理 604B80[0+result]=604B80[0+result]^v3
result = byte_6010C0[i + 1];
*(&byte_604B80 + result) ^= v3;
break;
case 4u:
result = byte_6010C0[i + 1]; // 同理 604B80[0+result]=604B80[0+result]*v3
*(&byte_604B80 + result) *= v3;
break;
case 5u:
result = byte_6010C0[i + 1]; // 下面等号右面的意思:604B80[0+v3],byte_6010C0[i+2]==V3
*(&byte_604B80 + result) ^= *(&byte_604B80 + byte_6010C0[i + 2]);// 这句代码意思:
// 604B80[0+result]=604B80[0+result]^604B80[0+v3]
//
// 这里byte_6010C0[i+2]的意思其实还是上面的V3
break;
default:
continue;
}
}
return result;
}
分析:
函数的意思:
根据6010C0处 6010C0[0] 6010C0[3] 6010C0[6]...6010C0[14997]来决定
对604B80的24个16进制数(即我们输入的字符串)进行 不同的操作
而操作后的604B80地址(指针)存放的24个16进制数(即我们输入的字符串经函数ub_4005B6()加密了)
最后604B80处的每个16进制数(字节)再与601060处每个双字的最后两位16进制数(即字节)要相等
逆向:
我们一切都逆着进行
我们的操作还是根据6010C0处 6010C0[0] 6010C0[3] 6010C0[6]...6010C0[14997]来决定
对604B80的24个16进制数(加密后的字符串==601060处每个双字的最后两位16进制数)进行 不同的操作
不过从14997到0进行循环操作
+换成-,*换成/ 亦或还是亦或(举例:0x8^0x3=0xB 0xB^0x3=0xB 0xB^0x8=0x3)
604B80[0+result]=604B80[0+result]-v3
604B80[0+result]=604B80[0+result]+v3
604B80[0+result]=604B80[0+result]^v3
604B80[0+result]=604B80[0+result]/v3
604B80[0+result]=604B80[0+result]^604B80[0+v3]
脚本
#coding:utf8
da=open('export_results','rb')#导出的二进制形式的15000字节的数组
bianhua=[0xC4,0X34,0x22,0xB1,0xD3,0x11,0x97,0x7,0xDB,0x37,0xC4,0x6,0x1D,0xFC,0x5B,0xED,0x98,0xDF,0x94,0xD8,0xB3,0x84,0xCC,0x8]
#bianhua对应的是 601060处的数据,每个双字的最后两位16进制数手动敲上去的
#流下没有技术的泪。
dashuzu=[]
for i in range(0,15000):
temp=da.readline(1)
dashuzu.append(ord(temp))
#print(dashuzu)
da.close()
for i in range(14997,-1,-3):
v0=dashuzu[i]
v3=dashuzu[i+2]
result=v0
if v0==1:
result=dashuzu[i+1]
bianhua[result]-=v3
elif v0==2:
result=dashuzu[i+1]
bianhua[result]+=v3
elif v0==3:
result=dashuzu[i+1]
bianhua[result]^=v3
elif v0==4:
result=dashuzu[i+1]
bianhua[result]/=v3
elif v0==5:
result=dashuzu[i+1]
bianhua[result]^=bianhua[dashuzu[i+2]]
else:
continue
#print (bianhua)
flag=''
for j in bianhua:
flag+=chr(j%256)#保证数据可以正常转成字符
print flag
# nctf{Embr4ce_Vm_j0in_R3}
总结:
真的好菜,要抓紧了,超越萝卜 /(刷题是我快乐,或许吧,哈哈!)