这题主要考察选手动态调试。扔进exeinfope,32位exe,无壳
main程序,点进sub_4017D0看
sub_4017D0,可以看出是检测进程名称。找到for之前的汇编,尝试在动调的时候修改eip直接jmp到CloseHandle,又或者是自己patch一下,防止return 1,从而反反调试。patch教程参考链接
(留意这里的dword_406120,之后会讲)
sub_401930是个SEH异常反调试,可以参考源码
直接查看汇编,参考刚刚上面的源码,反调试的E9刚好起到了花指令的作用,变成了jmp near ptr 8B762D3Ah。在jmp按一下U,在E9下面按c转为代码,然后再把E9 nop掉。

没红色了那就F5一下,按两下进sub_401960(再留意一下dword_406120)

返回到主函数的汇编,发现藏起来了一个函数sub_401FB0
又或者用shift+f12找到关键字符,对着Format按一下x键,找到调用的地方,然后再F5一下
找到了验证函数,先来看_Initialize_parallel_init_info函数
发现了NtSetInformationThread,这整个函数是隐藏线程防止调试用的,参考链接,直接eip修改过就行
(再留意一下dword_406120)
再看主函数里面的加密函数sub_401CD0,可看出来应该是做了加密的函数,解密后动态调用

发现是用之前看到的dword_406120解密的,当反调试函数都过了,让dword_406120+=了21,21,14,即dword_406120(下面改成了unk_406120)为56时才解密成功,从而调用函数。
右键Jump in a new hex window ->找到15h右键Edit->改成38(即十进制56)再右键Apply changes。


成功解码之后再慢慢步入进加密函数,当中加了花指令,花指令可参考安全客
我出题的时候发现有时候jnz没跳转,所以又加了test eax, eax
所以整个花指令模式如下
__asm{test eax, eax__emit(0x75) //jnz $+4__emit(0x02)__emit(0xE9) //干扰IDA__emit(0xED)}
这个花指令和上面是同一个,用的E9,参考上面的做法patch一下,把E9,ED nop掉

在最上面的push ebp右键 create function,成功建立函数后就可以F5了,图片这个实际上就是异或运算,都是按位运算,试一下就会发现是异或
以此类推,发现运算分别为加减乘除异或和取余66666(十六进制0x1046A,小彩蛋),其中除1等于没效果,取余66666还是调用了rand,所以还原加密过程的时候还是要保留



可以看出可以单字节爆破,还原一次加密过程,再爆破就得到flag了(导出加密的数据不细说了,shift+e)
#include<stdlib.h>#include<stdio.h>#include<iostream>#define rand100 rand()%100+1const char enflag[] = {0x0C,0x17,0x80,0x40,0x29,0x34,0x0C,0x29,0x28,0xA1,0x3A,0x80,0x82,0x1D,0x00,0x18,0xC3,0xCA,0x10,0x2E,0xD3,0x21,0x48,0xA5,0x3A,0x99,0xFB,0x46,0x0F,0xC6,0x78};void gen_rand(){srand(0);for(int i=0;i<31;i++){if(i%2==0)printf("\n");for(int j=0;j<5;j++){printf("0x%02X,",rand100);}}}const char random_list[] = {0x27,0x14,0x27,0x26,0x38,0x62,0x42,0x56,0x33,0x0D,0x36,0x01,0x2B,0x52,0x26,0x16,0x2E,0x56,0x62,0x51,0x4D,0x5C,0x38,0x07,0x3A,0x18,0x52,0x29,0x1A,0x4F,0x2F,0x5B,0x29,0x58,0x08,0x26,0x0C,0x12,0x39,0x44,0x22,0x4F,0x18,0x58,0x62,0x55,0x0D,0x0C,0x4F,0x43,0x1E,0x05,0x50,0x06,0x59,0x32,0x1E,0x4D,0x20,0x41,0x0F,0x25,0x1D,0x03,0x35,0x05,0x26,0x39,0x63,0x49,0x62,0x0E,0x54,0x04,0x3D,0x2B,0x30,0x4C,0x48,0x05,0x4A,0x35,0x14,0x05,0x28,0x57,0x05,0x26,0x18,0x24,0x22,0x5E,0x15,0x4B,0x54,0x3E,0x19,0x42,0x46,0x1F,0x44,0x25,0x32,0x25,0x14,0x1C,0x01,0x18,0x17,0x4B,0x0C,0x3F,0x42,0x5C,0x14,0x30,0x33,0x15,0x23,0x45,0x19,0x4E,0x2F,0x20,0x3B,0x49,0x1F,0x23,0x52,0x24,0x44,0x3D,0x0F,0x2B,0x4D,0x1C,0x18,0x5F,0x45,0x2D,0x19,0x16,0x08,0x61,0x1B,0x40,0x29,0x3F,0x30,0x51,0x30,0x1D,0x0E,0x54,0x3C};char encode(int input,int i){input ^= random_list[i*5];input += random_list[i*5+1];input *= random_list[i*5+2];input -= random_list[i*5+3];input %= 66666;return input&0xFF;}void brute(){for(int i=0;i<31;i++){for(int j=33;j<125;j++){if(encode(j,i) == enflag[i]){printf("%c",j);//break;}}printf("x");}}int main(){brute();}
我出题出的比较烂,直接多解算了
MOCSCTF{cRa0k_M3_1s_s0_Ea3y!!!}
MOCSCTF{CRa0k_M3_1s_s0_Ea3y!!!}
MOCSCTF{CRA0k_M3_1s_s0_Ea3y!!!}
MOCSCTF{cRA0k_M3_1s_s0_Ea3y!!!}
后记
(更新于2021.03.16)做了一题VNCTF确实下次可以弄个md5限制一下多解,例如这题套个md5就能防止多解
