三年三班三井寿 发表于 2020-10-10 17:09

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);
      }
```

re1wn 发表于 2020-10-10 22:11

|矢空 发表于 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
```

andytong123 发表于 2020-10-10 19:22

不明觉厉,一脸懵逼的路过

jige123 发表于 2020-10-10 17:21

感谢大佬分享,学习学习

凌云科技 发表于 2020-10-10 17:22

膜拜大佬看不懂啊

MrKang 发表于 2020-10-10 17:37

感觉这些对于楼主就是小菜一碟

whatcos 发表于 2020-10-10 17:45

大佬,我实话告诉你吧,我看不懂

wysyz 发表于 2020-10-10 18:31

大佬,我实话告诉你吧,我看不懂

|矢空 发表于 2020-10-10 19:01

能具体说一下是怎么去混淆的吗

re1wn 发表于 2020-10-10 19:10

师傅,脚本启动器的混淆代码如何去除?

|矢空 发表于 2020-10-10 19:12

re1wn 发表于 2020-10-10 19:10
师傅,脚本启动器的混淆代码如何去除?

我试了下,用火绒剑可以提取CMD内的字符串ode -d 114514,但不能完整恢复
页: [1] 2 3 4
查看完整版本: 2020西湖论剑 re-loader