前言
论坛和网上还有很多解析,每个人思路有所不同有兴趣的可以结合着看。
Simulator
这题的提示是Study 《Introduction to Computer System》 carefully,the format of flag is GACTF{},意思让我们好好学习计算机系统概论,计算机系统概论是一门计算机专业课,我们还没有教这门课。 我们下面下载题目后看到题目是一个OBJ文件,懵逼OBJ文件怎么逆向吗!
不管了用WinHex打开看一下,发现一些关键字符。我们可以看到字符串意思是
Welcome to the world of LC3
Please input you flag:
Sussess!
Your flag is xctf{{you input}}
Try again!
Welcome to the world of LC3,从来没有听说过LC3是什么东西。这时我想到了那句提示Study 《Introduction to Computer System》 carefully,那咱们就百度一下搜一搜《计算机系统概论》,还真发现了LC3。原来LC3是一款较为成熟的16位汇编程序运行调试软件,2003年时由美国得克萨斯州立大学的 Yale N. Patt 和伊利诺伊大学香槟分校的 Sanjay J. Patel 两位计算机科学教授开发完成。
我们需要下载LC-3模拟器,一般这个模拟器会包含一个供编写LC3汇编程序的软件LC3Edit.exe,一般用LC3Edit.exe编写LC3汇编程序会生成一个OBJ文件供用户调试,调试此OBJ文件的软件为Simulate.exe。
我们打开Simulate软件并导入OBJ文件,下面我们可以看到程序的LC3汇编代码。我在做的时候因为没接触过LC3汇编,上网搜结果资料及其少。不知道每一条指令的意思只好一步一步跟然后自己猜测并结合网上极其少的LC3汇编指令的注解将程序的主要逻辑搞明白了。
对其LC3代码的主要逻辑与算法逆向分析如下
Memory:
x3000 1110000001111010 xE07A LEA R0, x307B
x3001 1111000000100010 xF022 TRAP PUTS //向屏幕输出字符串:“Welcome to the world of LC3”
x3002 0010000001110111 x2077 LD R0, x307A
x3003 1111000000100001 xF021 TRAP OUT
x3004 1110000010010010 xE092 LEA R0, x3097
x3005 1111000000100010 xF022 TRAP PUTS //向屏幕输出字符串:"Please input you flag: "
x3006 0010011011011110 x26DE LD R3, x30E5 //R3 = 0x18
x3007 1111000000100000 xF020 TRAP GETC //获得屏幕的输入的一个字符
x3008 1111000000100001 xF021 TRAP OUT //将此字符显示到屏幕上
x3009 0010001011011010 x22DA LD R1, x30E4 //R1 = 0x4000
x300A 0001001001000011 x1243 ADD R1, R1, R3 //R1 = R1 + R3
x300B 0111000001000000 x7040 STR R0, R1, #0 //[R1] = R0
x300C 0001011011111111 x16FF ADD R3, R3, #-1 //R3 = R3 - 1
x300D 0000100000000001 x0801 BRN x300F //if(R3 == 0)跳转0x300F
x300E 0000111111111000 x0FF8 BRNZP x3007 //无条件跳转到0x3007
x300F 1110100011101111 xE8EF LEA R4, x30FF //以上指令主要功能就是获得0x19个字符并将其倒序保存在0x4000开始的连续的内存空间中
x3010 0101010010100000 x54A0 AND R2, R2, #0
x3011 0001001010000100 x1284 ADD R1, R2, R4
x3012 0110001001000000 x6240 LDR R1, R1, #0
x3013 0101000000100000 x5020 AND R0, R0, #0
x3014 0010000001100010 x2062 LD R0, x3077
x3015 1001000000111111 x903F NOT R0, R0
x3016 0001000000100001 x1021 ADD R0, R0, #1
x3017 0001000001000000 x1040 ADD R0, R1, R0
x3018 0000010000001010 x040A BRZ x3023
x3019 0010000001011110 x205E LD R0, x3078
x301A 1001000000111111 x903F NOT R0, R0
x301B 0001000000100001 x1021 ADD R0, R0, #1
x301C 0001000001000000 x1040 ADD R0, R1, R0
x301D 0000010000010111 x0417 BRZ x3035
x301E 0010000001011010 x205A LD R0, x3079
x301F 1001000000111111 x903F NOT R0, R0
x3020 0001000000100001 x1021 ADD R0, R0, #1
x3021 0001000001000000 x1040 ADD R0, R1, R0
x3022 0000010000100101 x0425 BRZ x3048
x3023 0001001010100001 x12A1 ADD R1, R2, #1
x3024 0001001100000001 x1301 ADD R1, R4, R1
x3025 0110001001000000 x6240 LDR R1, R1, #0
x3026 0001110001100000 x1C60 ADD R6, R1, #0
x3027 0001001010100010 x12A2 ADD R1, R2, #2
x3028 0001001100000001 x1301 ADD R1, R4, R1
x3029 0110001001000000 x6240 LDR R1, R1, #0
x302A 0010000010111001 x20B9 LD R0, x30E4
x302B 0001000001100000 x1060 ADD R0, R1, #0
x302C 0110000000000000 x6000 LDR R0, R0, #0
x302D 0001111000100000 x1E20 ADD R7, R0, #0
x302E 0001101001100000 x1A60 ADD R5, R1, #0
x302F 0000111000101001 x0E29 BRNZP x3059
x3030 0010001010110011 x22B3 LD R1, x30E4
x3031 0001001101000001 x1341 ADD R1, R5, R1
x3032 0111000001000000 x7040 STR R0, R1, #0
x3033 0001010010100011 x14A3 ADD R2, R2, #3
x3034 0000111111011100 x0FDC BRNZP x3011
x3035 0001001010100001 x12A1 ADD R1, R2, #1
x3036 0001001100000001 x1301 ADD R1, R4, R1
x3037 0110001001000000 x6240 LDR R1, R1, #0
x3038 0010000010101011 x20AB LD R0, x30E4
x3039 0001000000000001 x1001 ADD R0, R0, R1
x303A 0110110000000000 x6C00 LDR R6, R0, #0 //R6 = flag[0x18 - n - 1]
x303B 0001001010100010 x12A2 ADD R1, R2, #2
x303C 0001001100000001 x1301 ADD R1, R4, R1
x303D 0110001001000000 x6240 LDR R1, R1, #0
x303E 0010000010100101 x20A5 LD R0, x30E4
x303F 0001000000000001 x1001 ADD R0, R0, R1
x3040 0001101001100000 x1A60 ADD R5, R1, #0 //R5 = n
x3041 0110111000000000 x6E00 LDR R7, R0, #0 //R7 = flag[0x18 - n]
x3042 0000111000011000 x0E18 BRNZP x305B //jmp 0x305B
x3043 0010001010100000 x22A0 LD R1, x30E4 //R1 = 0x4000
x3044 0001001001000101 x1245 ADD R1, R1, R5 //R1 = R1 + R5
x3045 0111000001000000 x7040 STR R0, R1, #0 //[R1] = R0
x3046 0001010010100011 x14A3 ADD R2, R2, #3
x3047 0000111111001001 x0FC9 BRNZP x3011 //jmp 0x3011
x3048 0001001010100001 x12A1 ADD R1, R2, #1
x3049 0001001100000001 x1301 ADD R1, R4, R1
x304A 0110001001000000 x6240 LDR R1, R1, #0
x304B 0001110001100000 x1C60 ADD R6, R1, #0 //R6 = n
x304C 0001001010100010 x12A2 ADD R1, R2, #2
x304D 0001001100000001 x1301 ADD R1, R4, R1
x304E 0110001001000000 x6240 LDR R1, R1, #0
x304F 0010101010010101 x2A95 LD R5, x30E5
x3050 1001001001111111 x927F NOT R1, R1
x3051 0001001001100001 x1261 ADD R1, R1, #1
x3052 0001101101000001 x1B41 ADD R5, R5, R1 //R5 = 0x18 - n
x3053 0001111101100000 x1F60 ADD R7, R5, #0 //R7 = R5
x3054 0000111000001100 x0E0C BRNZP x3061 //jmp 0x3061
x3055 0001101101100000 x1B60 ADD R5, R5, #0 //关键跳转
x3056 0000010000010101 x0415 BRZ x306C //if(n == 0),则跳到0x306C,flag正确
x3057 0001010010100011 x14A3 ADD R2, R2, #3
x3058 0000111110111000 x0FB8 BRNZP x3011
x3059 0001000110000111 x1187 ADD R0, R6, R7
x305A 0000111111010101 x0FD5 BRNZP x3030
x305B 1001000110111111 x91BF NOT R0, R6
x305C 0101000000000111 x5007 AND R0, R0, R7 //R0 = ~R6 & R7
x305D 1001001111111111 x93FF NOT R1, R7
x305E 0101001110000001 x5381 AND R1, R6, R1 //R1 = ^R7 & R6
x305F 0001000001000000 x1040 ADD R0, R1, R0 //R0 = R0 + R1
x3060 0000111111100010 x0FE2 BRNZP x3043 //jmp 0x3043
x3061 0010000010000010 x2082 LD R0, x30E4
x3062 0001000000000110 x1006 ADD R0, R0, R6
x3063 0110000000000000 x6000 LDR R0, R0, #0 //R0 = 0x4000[n]
x3064 1110001010000001 xE281 LEA R1, x30E6
x3065 0001001001000111 x1247 ADD R1, R1, R7
x3066 0110001001000000 x6240 LDR R1, R1, #0 //R1 = 0x30EF[0x18 - n]
x3067 1001001001111111 x927F NOT R1, R1
x3068 0001001001100001 x1261 ADD R1, R1, #1 //关键判断,跳转处
x3069 0001000000000001 x1001 ADD R0, R0, R1 //if(R0 == R1)
x306A 0000010111101010 x05EA BRZ x3055 //jmp 0x3055
x306B 0000111000000101 x0E05 BRNZP x3071
x306C 0010000000001101 x200D LD R0, x307A //输出Success!
x306D 1111000000100001 xF021 TRAP OUT
x306E 1110000001000000 xE040 LEA R0, x30AF //输出Your flag is xctf{{you input}}
x306F 1111000000100010 xF022 TRAP PUTS
x3070 0000111000000101 x0E05 BRNZP x3076
x3071 0010000000001000 x2008 LD R0, x307A //输出Try again!
x3072 1111000000100001 xF021 TRAP OUT
x3073 1110000001100101 xE065 LEA R0, x30D9 //输出----- Halting the processor -----
x3074 1111000000100010 xF022 TRAP PUTS
x3075 0000111000000000 x0E00 BRNZP x3076
x3076 1111000000100101 xF025 TRAP HALT
x3077 0000000000010001 x0011 NOP
x3078 0000000000010011 x0013 NOP
x3079 0000000000010100 x0014 NOP
算法大致就是对25个字符的flag进行加密后与0x30EF内存处的数组进行比较,我们在winHex中可以找到此数组的数据
而且由算法逆向可知,我们输入的flag的第一个字符必须为‘l’即值等于0x6c,最后我们根据其算法编写程序得到flag为:lc3_1s_small_but_complete
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
BYTE a[25];
BYTE b[25];
BYTE F[] ={0x6C, 0x0f, 0x50, 0x6c, 0x6e, 0x42, 0x2c, 0x2c, 0x1e,
0x0c, 0x0d, 0x0, 0x33, 0x3d, 0x17, 0x01, 0x2b,
0x3c, 0x0c, 0x02, 0x1d, 0x1c, 0x09, 0x11, 0x11};
BYTE R1;
BYTE R0;
BYTE R5 = 24;
BYTE R6 = 0;
BYTE R7 = 24;
for(int i = 0;i <= 24; i++)
{
R7 = 24 - i;
R1 = F[R7];
R1 = ~R1;
R1 = R1 + 1;
b[i] = R1;
}
BYTE yy2 = 1;
BYTE yy1 = 1;
BYTE rr = 1;
BYTE yy11;
while(1)
{
while(yy2 < 0xff)
{
yy1 = 1;
while(yy1 < 0xff)
{
rr = (((~yy1) & yy2) + ((~yy2) & yy1) + b[0]);
if(rr == 0)
{
if((yy1 >=0x21 && yy1<= 0x7e) && (yy2 >=0x21 && yy2<= 0x7e))
{
rr = 2;
break;
}
}
yy1++;
}
if(rr == 2)
break;
yy2++;
}
a[24] = yy2;
a[23] = yy1;
for(int i = 23; i >= 1; i--)
{
yy11 = 1;
while(yy11 < 0xff)
{
rr = (((~yy11) & a[i]) + ( ~a[i] & yy11) + b[24 - i]);
if(rr == 0)
{
if((yy11 >=0x21 && yy11<= 0x7e) && (yy2 >=0x21 && yy2<= 0x7e))
break;
}
yy11++;
}
a[i-1] = yy11;
}
if(a[0] == 'l')
break;
yy2++;
rr = 0;
}
printf("flag:%.24s\n", a);
return 0 ;
}
下面是我在寻找LC3汇编时候搜的的一些资源,关于LC3汇编调试器的使用,以及其指令系统,有兴趣的可以看看。
https://my.oschina.net/Samyan/blog/1614174/print
https://wenku.baidu.com/view/c322be9ab14e852459fb573b.html
WannaFlag
此软件我们用Exeinfope分析后得其为32位可执行文件,无壳。
然后我们直接拖入OD运行,软件的页面有点防勒索软件的意思,并且放着诡异的音乐。其提示为需要输入正确的KEY,从而获得flag。还可以支付给作者6666人民币获得,可笑身为吾爱破解的资深菜鸟怎么可能丢这个人。准备开干!
按照一般思路,其让输入key并判断key,那就肯定需要获取edit控件的key值。对一些获取edit控件值的API下断点,如GetWindowTextA/W,GetDlgItemTextA/W等等。
我们输入123456位key后按DECRYPT FLAG。程序断在了GetWindowTextA函数的入口处。
接着我们ALT+F9返回到用户空间中。我们往下看发现其调用MessagBoxA显示orz,意思就是我们成功了。其上方的一些跳转都是关键跳转。我们往上分析汇编代码的含义及其算法实现。
005D2847 . 83C4 0C add esp,0xC
005D284A . 8D8424 200200>lea eax,dword ptr ss:[esp+0x220]
005D2851 . 6A 20 push 0x20 ; /Count = 20 (32.)
005D2853 . 50 push eax ; |Buffer
005D2854 . 56 push esi ; |hWnd
005D2855 . FF15 FCB15E00 call Xdword ptr ds:[0x5EB1FC] ; \GetWindowTextA
005D285B . 8DB424 200200>lea esi,dword ptr ss:[esp+0x220]
005D2862 . 8D4E 01 lea ecx,dword ptr ds:[esi+0x1]
005D2865 > 8A06 mov al,byte ptr ds:[esi]
005D2867 . 46 inc esi
005D2868 . 84C0 test al,al
005D286A .^ 75 F9 jnz X005D2865
005D286C . 2BF1 sub esi,ecx
005D286E . 83FE 06 cmp esi,0x6
005D2871 . 0F8C 6A010000 jl 005D29E1 ; esi = key长度
005D2877 . 0FBE8424 2402>movsx eax,byte ptr ss:[esp+0x224]
005D287F . B9 07000000 mov ecx,0x7
005D2884 . 99 cdq
005D2885 . F7F9 idiv ecx ; edi = a[4] % 7
005D2887 . 8BFA mov edi,edx
005D2889 . 8D51 FA lea edx,dword ptr ds:[ecx-0x6] ; edx = 1
005D288C . B9 02000000 mov ecx,0x2 ; ecx = 2
005D2891 . 3BF9 cmp edi,ecx
005D2893 . 7E 08 jle X005D289D
005D2895 > 0FAFD1 imul edx,ecx ; edx * ecx
005D2898 . 41 inc ecx ; ecx = 3
005D2899 . 3BCF cmp ecx,edi
005D289B .^ 7C F8 jl X005D2895
005D289D > 33C0 xor eax,eax
005D289F . 83FE 40 cmp esi,0x40
005D28A2 . 0F82 7F000000 jb 005D2927
005D28A8 . 8BCE mov ecx,esi
005D28AA . 81E1 3F000080 and ecx,0x8000003F
005D28B0 . 79 05 jns X005D28B7
005D28B2 . 49 dec ecx
005D28B3 . 83C9 C0 or ecx,0xFFFFFFC0
005D28B6 . 41 inc ecx
005D28B7 > 8BFE mov edi,esi
005D28B9 . 2BF9 sub edi,ecx
005D28BB . 0FBECA movsx ecx,dl
005D28BE . 66:0F6EC1 movd mm0,ecx
005D28C2 . 66:0F60C0 punpcklbw mm0,mm0
005D28C6 . 66:0F61C0 punpcklwd mm0,mm0
005D28CA . 66:0F70C8 00 pshufw mm1,mm0,0x0
005D28CF . 90 nop
005D28D0 > 0F108404 2002>movups xmm0,dqword ptr ss:[esp+eax+0x220>
005D28D8 . 66:0FEFC1 pxor mm0,mm1
005D28DC . 0F118404 7802>movups dqword ptr ss:[esp+eax+0x278],xmm>
005D28E4 . 0F108404 3002>movups xmm0,dqword ptr ss:[esp+eax+0x230>
005D28EC . 66:0FEFC1 pxor mm0,mm1
005D28F0 . 0F118404 8802>movups dqword ptr ss:[esp+eax+0x288],xmm>
005D28F8 . 0F108404 4002>movups xmm0,dqword ptr ss:[esp+eax+0x240>
005D2900 . 66:0FEFC1 pxor mm0,mm1
005D2904 . 0F118404 9802>movups dqword ptr ss:[esp+eax+0x298],xmm>
005D290C . 0F108404 5002>movups xmm0,dqword ptr ss:[esp+eax+0x250>
005D2914 . 66:0FEFC1 pxor mm0,mm1
005D2918 . 0F118404 A802>movups dqword ptr ss:[esp+eax+0x2A8],xmm>
005D2920 . 83C0 40 add eax,0x40
005D2923 . 3BC7 cmp eax,edi
005D2925 .^ 7C A9 jl X005D28D0
005D2927 > 3BC6 cmp eax,esi
005D2929 . 7D 1A jge X005D2945
005D292B 0F db 0F
005D292C 1F db 1F
005D292D 44 db 44 ; CHAR 'D'
005D292E 00 db 00
005D292F 00 db 00
005D2930 > 8A8C04 200200>mov cl,byte ptr ss:[esp+eax+0x220] ; cl = key[n]
005D2937 . 32CA xor cl,dl ; cl = cl ^ dl
005D2939 . 888C04 780200>mov byte ptr ss:[esp+eax+0x278],cl ; 0x003ff9A0[n] = cl
005D2940 . 40 inc eax ; n++
005D2941 . 3BC6 cmp eax,esi
005D2943 .^ 7C EB jl X005D2930 ; ------------
005D2945 > C68404 780200>mov byte ptr ss:[esp+eax+0x278],0x0
005D294D . 33D2 xor edx,edx
005D294F . 90 nop
005D2950 > 8A82 E00A5F00 mov al,byte ptr ds:[edx+0x5F0AE0] ; al = 0x00CE0AE1[n]
005D2956 . 8ACA mov cl,dl
005D2958 . 328414 780200>xor al,byte ptr ss:[esp+edx+0x278] ; al = al ^ 0x003ff9A0[n]
005D295F . D2C0 rol al,cl ; rol al , n
005D2961 . 888414 780200>mov byte ptr ss:[esp+edx+0x278],al ; 0x003ff9A0[n] = AL
005D2968 . 42 inc edx
005D2969 . 3BD6 cmp edx,esi
005D296B .^ 7C E3 jl X005D2950 ; ---------------------
005D296D . 8D8C24 780200>lea ecx,dword ptr ss:[esp+0x278]
005D2974 . BA D8785F00 mov edx,0x5F78D8 ; 全局数组0x5f78d8
005D2979 . BE 1B000000 mov esi,0x1B ; esi = 0x1B
005D297E . 66:90 nop
005D2980 > 8B01 mov eax,dword ptr ds:[ecx] ; 判断加密后的key与0x5F78D8内存处数组的数据是否相等
005D2982 . 3B02 cmp eax,dword ptr ds:[edx]
005D2984 75 5B jnz X005D29E1
005D2986 . 83C1 04 add ecx,0x4
005D2989 . 83C2 04 add edx,0x4
005D298C . 83EE 04 sub esi,0x4
005D298F .^ 73 EF jnb X005D2980
005D2991 . 66:8B01 mov ax,word ptr ds:[ecx]
005D2994 . 66:3B02 cmp ax,word ptr ds:[edx]
005D2997 . 75 48 jnz X005D29E1
005D2999 . 8A41 02 mov al,byte ptr ds:[ecx+0x2]
005D299C . 3A42 02 cmp al,byte ptr ds:[edx+0x2]
005D299F . 75 40 jnz X005D29E1
005D29A1 . 6A 00 push 0x0 ; /Style = MB_OK|MB_APPLMODAL
005D29A3 . 68 980C5F00 push 0x5F0C98 ; |Title = "orz"
005D29A8 . 68 980C5F00 push 0x5F0C98 ; |Text = "orz"
005D29AD . 53 push ebx ; |hOwner
005D29AE . FF15 00B25E00 call Xdword ptr ds:[0x5EB200] ; \MessageBoxA
我们在内存窗口中查看0x5f78d8地址处的数组的数据。
接着我们根据逆向算法写出程序求得真正的key为:wannaflag_is_just_a_paper_tiger
需要注意的是rol运算的逆向在c语言ror指令的实现注意字节的大小,解密程序如下。
#include <iostream>
#include <Windows.h>
using namespace std;
#include <stdio.h>
unsigned ror(unsigned val, int size);
int main()
{
BYTE a[32] = {0};
BYTE b[ ] = { 0x4E, 0xAE, 0x61, 0xBA, 0xE4, 0x2B, 0x55, 0xAA, 0x59, 0xFC, 0x4D, 0x02, 0x17, 0x6B, 0x13, 0xA1,
0x41, 0xFE, 0x35, 0x0B, 0xB4, 0x0B, 0x52, 0x2F, 0x46, 0xCC, 0x35, 0x82, 0xE5, 0x88, 0x50};
BYTE c[ ] = "ANNAWGALFYBKVIAHMXTFCAACLAAAAYK";
BYTE d[32] = {0};
for(int i = 0; i < 31; i++)
{
a[i] = ror(b[i],i) ^ c[i];
}
BYTE flag = 0;
while(1)
{
for(int i = 0; i < 31; i++)
{
d[i] = flag ^ a[i];
}
BYTE WW = 2;
BYTE WW2 = 1;
while((d[4] % 7) > WW)
{
WW2 = WW2 * WW;
WW++;
}
if(flag == WW2)
break;
flag++;
}
printf("flag:%s\n", d);
}
unsigned ror(unsigned val, int size)
{
unsigned res = val >> (size) % 8;
res |= val << (8 - (size % 8)) ;
return res;
}
接着输入正确的key后用OD我们运行程序,发现程序利用key和flag.bin中的数据结合解密函数得到flag。并生成flag.txt文件,将flag写进去。
Checkin
还是用Excinfope程序查壳,发现文件为32位程序无壳直接载入OD。
我们单步向下跟踪发现岂会利用内存映射文件,将自身文件的附件数据通过创建文件并写入。
接着单步往下跟踪我们发现其实际是在路径C:\Users\ADMINI~1\AppData\Local\Temp\ocrA147.tmp下创建大量文件。
我们继续向下单步跟踪发现岂会创建一个新的进程,C:\Users\ADMINI~1\AppData\Local\Temp\ocrA147.tmp\bin\ruby.exe。此程序也是刚刚程序自己生成的文件。其通过CteateProessA创建此程序后,调用WaitForSingleObject()函数等待进程返回(此函数为阻塞函数)。当进程返回后程序调用GetExitCodeProess()获得程序结束的代码作进一步处理。
我们在WaitForSingleObject调用的下一条指令下断点,运行程序输入flag回车后,显示no,且WaitForSingleObjet函数返回,程序中断在刚刚下的断点处。
我们查看程序为单线程,所以不可能是此程序的其他线程进行的flag的判断。所以肯定是CreateProessA创建的Ruby.exe进行的判断。
我们来到ruby程序的文件夹下发现实际此程序是ruby编程语言脚本的执行程序。
我们在C:\Users\Administrator\AppData\Local\Temp\ocrA147.tmp\src目录下找到待执行的rb文件,其代码如下主要是采用了aes和base64加密。
require 'openssl'
require 'base64'
def aes_encrypt(key,encrypted_string)
aes = OpenSSL::Cipher.new("AES-128-ECB")
aes.encrypt
aes.key = key
cipher = aes.update(encrypted_string) << aes.final
return Base64.encode64(cipher)
end
print "Enter flag: "
flag = gets.chomp
key = "Welcome_To_GACTF"
cipher = "4KeC/Oj1McI4TDIM2c9Y6ahahc6uhpPbpSgPWktXFLM=\n"
text = aes_encrypt(key,flag)
if cipher == text
puts "good!"
else
puts "no!"
End
我们由加密程序写出解密程序,代码如下
require 'openssl'
require 'base64'
def aes_dicrypt(key,dicrypted_string)
cipher = Base64.decode64(dicrypted_string)
aes = OpenSSL::Cipher.new("AES-128-ECB")
aes.decrypt
aes.key = key
cipher = aes.update(cipher) << aes.final
return cipher
end
key = "Welcome_To_GACTF"
cipher = "4KeC/Oj1McI4TDIM2c9Y6ahahc6uhpPbpSgPWktXFLM=\n"
flag = aes_dicrypt(key,cipher)
printf("flag:%s\n",flag)
在cmd命令行运行程序得到flag。
我同时好奇其是如何从一个程序(ruby.exe)在另一个程序的cmd获得控制台输入的,经过对ruby的逆向分析发现。其实通过建立与Checkin.exe程序之间的管道,ruby.exe通过管道借助ReadFile()函数来获得Checkin.exe的控制台的输入的。