2020西湖论剑 re-loader
本帖最后由 三年三班三井寿 于 2020-10-10 17:15 编辑挺久不碰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 == 0x2D && argv == 0x64 ) // -d
byte_40B068 = 1;
if ( byte_40B068 )
{
if ( argc <= 2 )
{
sub_408310("Error\n");
exit(0);
}
i_114514 = atoi(argv);
sub_4017B0((char *)argv, i_114514);
sub_401A6E(TempFileName);
}
sub_401A6E((char *)argv);
}
```
在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:
00ADD432 B9 36000000 MOV ECX,0x36
00ADD437 B8 CCCCCCCC MOV EAX,0xCCCCCCCC
00ADD43C F3:AB REP STOS DWORD PTR ES:
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:,0x0 ; i=0
00ADD489 EB 09 JMP SHORT 00ADD494
00ADD48B 8B45 F8 MOV EAX,DWORD PTR SS:
00ADD48E 83C0 01 ADD EAX,0x1
00ADD491 8945 F8 MOV DWORD PTR SS:,EAX
00ADD494 837D F8 20 CMP DWORD PTR SS:,0x20
00ADD498 7D 3B JGE SHORT 00ADD4D5 ; for(i=0;i<0x20;i++)
00ADD49A 8B45 F8 MOV EAX,DWORD PTR SS:
00ADD49D 0FB688 888EBB00 MOVZX ECX,BYTE PTR DS: ; ecx=str
00ADD4A4 8B45 F8 MOV EAX,DWORD PTR SS:
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=str_PEFile
00ADD4B6 8B45 F8 MOV EAX,DWORD PTR SS:
00ADD4B9 0D E3000000 OR EAX,0xE3 ; i | 0xE3
00ADD4BE 03D0 ADD EDX,EAX ; edx=str_PEFile+(i | 0xE3)
00ADD4C0 8B45 F8 MOV EAX,DWORD PTR SS:
00ADD4C3 C1E0 04 SHL EAX,0x4 ; eax=i<<4
00ADD4C6 33D0 XOR EDX,EAX ; edx=(str_PEFile+(i | 0xE3))^(i<<4)
00ADD4C8 33CA XOR ECX,EDX
00ADD4CA 8B55 F8 MOV EDX,DWORD PTR SS:
00ADD4CD 888A 888EBB00 MOV BYTE PTR DS:,CL ; str^=edx
00ADD4D3^ EB B6 JMP SHORT 00ADD48B
00ADD4D5 C745 EC 0000000>MOV DWORD PTR SS:,0x0 ; j=0
00ADD4DC EB 09 JMP SHORT 00ADD4E7
00ADD4DE 8B45 EC MOV EAX,DWORD PTR SS:
00ADD4E1 83C0 01 ADD EAX,0x1
00ADD4E4 8945 EC MOV DWORD PTR SS:,EAX
00ADD4E7 837D EC 20 CMP DWORD PTR SS:,0x20
00ADD4EB 7D 2E JGE SHORT 00ADD51B ; for(j=0;j<0x20;j++)
00ADD4ED 8B45 EC MOV EAX,DWORD PTR SS:
00ADD4F0 0FB688 888EBB00 MOVZX ECX,BYTE PTR DS: ; ecx=str
00ADD4F7 8B55 EC MOV EDX,DWORD PTR SS:
00ADD4FA 0FB682 2880BB00 MOVZX EAX,BYTE PTR DS: ; eax=arr2
00ADD501 3BC8 CMP ECX,EAX ; str==arr2
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 ^= (str_PEFile + (i | 0xE3)) ^ (i << 4);
}
```
|矢空 发表于 2020-10-10 19:01
能具体说一下是怎么去混淆的吗
我不会去混淆,我就先让程序跑起来,再用x32dbg附加这个进程,输入字符后跟着往里走(有查断点的反调试,设置新运行点即可跳过),直到找到fail和win的字符串,选中整个主函数,右键snowman反编译,逻辑清晰,一较复杂的异或和最后的明文比较
```py
tmp=
stri='PEFile'
flag=
for i in range(0x20):
flag=(tmp^(ord(stri)+(i|0xe3)^i<<4))&0xff
print(flag)
print(''.join(map(chr,flag)))
#15cf4ce97a270960b10bed48b0cfe4b8
``` 不明觉厉,一脸懵逼的路过 感谢大佬分享,学习学习 膜拜大佬看不懂啊 感觉这些对于楼主就是小菜一碟 大佬,我实话告诉你吧,我看不懂 大佬,我实话告诉你吧,我看不懂 能具体说一下是怎么去混淆的吗 师傅,脚本启动器的混淆代码如何去除?
re1wn 发表于 2020-10-10 19:10
师傅,脚本启动器的混淆代码如何去除?
我试了下,用火绒剑可以提取CMD内的字符串ode -d 114514,但不能完整恢复