挺久不碰win了,最近西湖论剑,晚上下班就随便看了看re的题。
这一题在re中应该算比较简单的,共三个文件loader.exe,code还有一个脚本启动器getflag.bat。
直接运行exe闪退,脚本有混淆,但也很容易去除。
去除混淆后脚本为:
@set @=
@set ;=
@set a=
@set b=
@set }=
@set c=
@set d=
@set ,=
@set e=
@set f=
@set g=
@set !=
@set h=
@set i=
@set j=
@set '=
@set k=
@set l=
@set m=
@set #=
@set n=
@set o=
@set )=
@set p=
@set q=
@set r=
@set _=
@set s=
@set t=
@set u=
@set (=
@set v=
@set $=
@set w=
@set x=
@set y=
@set {=
@set z=
@echo off
echo Your Password:
loader.exe code -d 114514
pause
前面一堆混淆的参数,有用的就是loader.exe code -d 114514。接着按着脚本设定的参数调试loader.exe即可。
loader实际上也就是对code解密加载,
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
int i_114514; // eax
sub_402870();
if ( argc <= 2 )
{
sub_408310("Error\n");
exit(0);
}
if ( *argv[2] == 0x2D && argv[2][1] == 0x64 ) // -d
byte_40B068 = 1;
if ( byte_40B068 )
{
if ( argc <= 2 )
{
sub_408310("Error\n");
exit(0);
}
i_114514 = atoi(argv[3]);
sub_4017B0((char *)argv[1], i_114514);
sub_401A6E(TempFileName);
}
sub_401A6E((char *)argv[1]);
}
在sub_4017B0中会从code中解密生成一个临时文件,code前8字节作为CRC校验值,以及解密的长度。之后在sub_401A6E中申请空间填入代码。这些以及填入的逻辑等等其实对于题目本身而言并不重要。
跟踪到输入验证部分,直接dump出代码即可。但我直接在od上没能dump下来,题目也比较简单,直接撸汇编也不需要什么时间:
00ADD420 55 PUSH EBP
00ADD421 8BEC MOV EBP,ESP
00ADD423 81EC D8000000 SUB ESP,0xD8
00ADD429 53 PUSH EBX
00ADD42A 56 PUSH ESI
00ADD42B 57 PUSH EDI
00ADD42C 8DBD 28FFFFFF LEA EDI,DWORD PTR SS:[EBP-0xD8]
00ADD432 B9 36000000 MOV ECX,0x36
00ADD437 B8 CCCCCCCC MOV EAX,0xCCCCCCCC
00ADD43C F3:AB REP STOS DWORD PTR ES:[EDI]
00ADD43E B9 2BC0BB00 MOV ECX,0xBBC02B
00ADD443 E8 14AFFFFF CALL 00AD835C
00ADD448 6A 28 PUSH 0x28
00ADD44A 68 888EBB00 PUSH 0xBB8E88
00ADD44F 68 700EB900 PUSH 0xB90E70 ; ASCII "%s"
00ADD454 E8 C1A0FFFF CALL <scanf> ; scanf
00ADD459 83C4 0C ADD ESP,0xC
00ADD45C 68 888EBB00 PUSH 0xBB8E88
00ADD461 E8 1D92FFFF CALL <strlen>
00ADD466 83C4 04 ADD ESP,0x4
00ADD469 83F8 20 CMP EAX,0x20
00ADD46C 74 14 JE SHORT 00ADD482
00ADD46E 68 740EB900 PUSH 0xB90E74 ; len(str)!=0x20,fail
00ADD473 E8 2690FFFF CALL 00AD649E
00ADD478 83C4 04 ADD ESP,0x4
00ADD47B 33C0 XOR EAX,EAX
00ADD47D E9 AD000000 JMP 00ADD52F
00ADD482 C745 F8 0000000>MOV DWORD PTR SS:[EBP-0x8],0x0 ; i=0
00ADD489 EB 09 JMP SHORT 00ADD494
00ADD48B 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-0x8]
00ADD48E 83C0 01 ADD EAX,0x1
00ADD491 8945 F8 MOV DWORD PTR SS:[EBP-0x8],EAX
00ADD494 837D F8 20 CMP DWORD PTR SS:[EBP-0x8],0x20
00ADD498 7D 3B JGE SHORT 00ADD4D5 ; for(i=0;i<0x20;i++)
00ADD49A 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-0x8]
00ADD49D 0FB688 888EBB00 MOVZX ECX,BYTE PTR DS:[EAX+0xBB8E88] ; ecx=str[i]
00ADD4A4 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-0x8]
00ADD4A7 99 CDQ
00ADD4A8 BE 06000000 MOV ESI,0x6
00ADD4AD F7FE IDIV ESI ; edx=i%6
00ADD4AF 0FBE92 2080BB00 MOVSX EDX,BYTE PTR DS:[EDX+0xBB8020] ; edx=str_PEFile[i%6]
00ADD4B6 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-0x8]
00ADD4B9 0D E3000000 OR EAX,0xE3 ; i | 0xE3
00ADD4BE 03D0 ADD EDX,EAX ; edx=str_PEFile[i%6]+(i | 0xE3)
00ADD4C0 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-0x8]
00ADD4C3 C1E0 04 SHL EAX,0x4 ; eax=i<<4
00ADD4C6 33D0 XOR EDX,EAX ; edx=(str_PEFile[i%6]+(i | 0xE3))^(i<<4)
00ADD4C8 33CA XOR ECX,EDX
00ADD4CA 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-0x8]
00ADD4CD 888A 888EBB00 MOV BYTE PTR DS:[EDX+0xBB8E88],CL ; str[i]^=edx
00ADD4D3 ^ EB B6 JMP SHORT 00ADD48B
00ADD4D5 C745 EC 0000000>MOV DWORD PTR SS:[EBP-0x14],0x0 ; j=0
00ADD4DC EB 09 JMP SHORT 00ADD4E7
00ADD4DE 8B45 EC MOV EAX,DWORD PTR SS:[EBP-0x14]
00ADD4E1 83C0 01 ADD EAX,0x1
00ADD4E4 8945 EC MOV DWORD PTR SS:[EBP-0x14],EAX
00ADD4E7 837D EC 20 CMP DWORD PTR SS:[EBP-0x14],0x20
00ADD4EB 7D 2E JGE SHORT 00ADD51B ; for(j=0;j<0x20;j++)
00ADD4ED 8B45 EC MOV EAX,DWORD PTR SS:[EBP-0x14]
00ADD4F0 0FB688 888EBB00 MOVZX ECX,BYTE PTR DS:[EAX+0xBB8E88] ; ecx=str[i]
00ADD4F7 8B55 EC MOV EDX,DWORD PTR SS:[EBP-0x14]
00ADD4FA 0FB682 2880BB00 MOVZX EAX,BYTE PTR DS:[EDX+0xBB8028] ; eax=arr2[i]
00ADD501 3BC8 CMP ECX,EAX ; str[i]==arr2[i]
00ADD503 74 14 JE SHORT 00ADD519
00ADD505 68 740EB900 PUSH 0xB90E74 ; ASCII "Fail\n"
00ADD50A E8 8F8FFFFF CALL 00AD649E
00ADD50F 83C4 04 ADD ESP,0x4
00ADD512 6A 00 PUSH 0x0
00ADD514 E8 2AB3FFFF CALL 00AD8843
00ADD519 ^ EB C3 JMP SHORT 00ADD4DE
00ADD51B 68 7C0EB900 PUSH 0xB90E7C ; ASCII "Win!\n"
00ADD520 E8 798FFFFF CALL 00AD649E
00ADD525 83C4 04 ADD ESP,0x4
00ADD528 6A 00 PUSH 0x0
00ADD52A E8 14B3FFFF CALL 00AD8843
00ADD52F 5F POP EDI
00ADD530 5E POP ESI
00ADD531 5B POP EBX
00ADD532 81C4 D8000000 ADD ESP,0xD8
00ADD538 3BEC CMP EBP,ESP
00ADD53A E8 EAAEFFFF CALL 00AD8429
00ADD53F 8BE5 MOV ESP,EBP
00ADD541 5D POP EBP
00ADD542 C3 RETN
首先就是对输入的长度限定为0x20,接着按字节将输入的字符串与"PEFile"计算异或。
最后再将异或后的字符串与另一组值比较即可。
通过输出也就能直接计算得到输入了:
BYTE str_PEFile[] = { 0x50, 0x45, 0x46, 0x69, 0x6c, 0x65 };
BYTE output[] = {
0x02, 0x0d, 0x6a, 0x1a, 0x27, 0x7f, 0x32, 0x65, 0x86, 0xa5, 0xc5, 0xd7, 0xcf, 0xdd, 0xe3, 0x98,
0x3d, 0x79, 0x53, 0x6a, 0x18, 0x54, 0x37, 0x14, 0xa9, 0xe0, 0x82, 0xb2, 0xce, 0x80, 0xcd, 0x8c
};
for (int i = 0; i < 0x20; ++i) {
output[i] ^= (str_PEFile[i % 6] + (i | 0xE3)) ^ (i << 4);
}