hacker re Re_0x01 CH0ico 2024-07-26 2024-07-26 RE_起点
0x01 Reversing-x64Elf-100 exeinfo 64 位 ELF 文件,无壳
IDA 分析 有 main 函数 , 跟进 (反编译)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 __int64 __fastcall main (int a1, char **a2, char **a3) { char s[264 ]; unsigned __int64 v5; v5 = __readfsqword(0x28 u); printf ("Enter the password: " ); if ( !fgets(s, 255 , stdin ) ) return 0LL ; if ( (unsigned int )sub_4006FD(s) ) { puts ("Incorrect password!" ); return 1LL ; } else { puts ("Nice!" ); return 0LL ; } }
经过一个 pass 的判断后执行 sub_4006FD( ) 跟进 sub_4006FD (反编译)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 __int64 __fastcall sub_4006FD (__int64 a1) { int i; __int64 v3[4 ]; v3[0 ] = (__int64)"Dufhbmf" ; v3[1 ] = (__int64)"pG`imos" ; v3[2 ] = (__int64)"ewUglpt" ; for ( i = 0 ; i <= 11 ; ++i ) { if ( *(char *)( v3[i % 3 ] + 2 * (i / 3 )) - *(char *)(i + a1) != 1 ) return 1LL ; } return 0LL ; }
猜测处理之后输出的是 flag
1 2 3 *(char *)( v3[i % 3 ] + 2 *(i / 3 ) ) = *(char *)( i+a1 ) + 1
编写 exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 key = ["Dufhbmf" ,"pG`imos" ,"ewUglpt" ] flag="" for i in range (12 ): flag += chr (ord ( key[i%3 ][2 *int (i/3 )] ) - 1 ) print (flag)
0x02 666 ELF 64bit obj. Shared obj file
main 函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int __fastcall main (int argc, const char **argv, const char **envp) { char s[240 ]; char v5[240 ]; memset (s, 0 , 0x1E uLL); printf ("Please Input Key: " ); __isoc99_scanf("%s" , v5); encode(v5, s); if ( strlen (v5) == key ) { if ( !strcmp (s, enflag) ) puts ("You are Right" ); else puts ("flag{This_1s_f4cker_flag}" ); } return 0 ; }
可以看到条件
1 2 3 4 5 6 __isoc99_scanf("%s" , v5); encode(v5, s); if ( strlen (v5) == key ) if ( !strcmp (s, enflag) )
同时跟进 key
1 .data:000004080 key dd 12 h
h 是十六进制 12(16) = 18(10) 所以 key 长度是 18 enflag = izwhroz””w”v.K”.NiASCII 文本,十六进制,二进制,十进制,Base64 转换器 (rapidtables.org) 换算成十进制 enflag = 105 122 119 104 114 111 122 34 34 119 34 118 46 75 34 46 78 105
encode 函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int __fastcall encode (const char *a1, __int64 a2) { char v3[104 ]; int v4; int i; i = 0 ; v4 = 0 ; if ( strlen (a1) != key ) return puts ("Your Length is Wrong" ); for ( i = 0 ; i < key; i += 3 ) { v3[i + 64 ] = key ^ (a1[i] + 6 ); v3[i + 33 ] = (a1[i + 1 ] - 6 ) ^ key; v3[i + 2 ] = a1[i + 2 ] ^ 6 ^ key; *(_BYTE *)(a2 + i) = v3[i + 64 ]; *(_BYTE *)(a2 + i + 1LL ) = v3[i + 33 ]; *(_BYTE *)(a2 + i + 2LL ) = v3[i + 2 ]; } return a2; }
针对
1 2 3 v3[i + 64 ] = 18 ^ (a1[i] + 6 ); v3[i + 33 ] = (a1[i + 1 ] - 6 ) ^ 18 ; v3[i + 2 ] = a1[i + 2 ] ^ 6 ^ 18 ;
a1
:一个指向字符数组的指针,表示要加密的字符串。
解密
1 2 3 4 5 6 7 enflag=[105 ,122 ,119 ,104 ,114 ,111 ,122 ,34 ,34 ,119 ,34 ,118 ,46 ,75 ,34 ,46 ,78 ,105 ] flag='' for i in range (0 ,18 ,3 ): flag+=chr ((18 ^enflag[i])-6 ) flag+=chr ((18 ^enflag[i+1 ])+6 ) flag+=chr ((18 ^enflag[i+2 ])^6 )
0x03 easyRE1 给了两个附件, x64 分析, 无壳
main 函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 int __fastcall main (int argc, const char **argv, const char **envp) { char s1[264 ]; unsigned __int64 v5; v5 = __readfsqword(0x28 u); puts ("What is the password?" ); gets(s1); if ( !strcmp (s1, "the password" ) ) puts ("FLAG:db2f62a36a018bce28e46d976e3f9864" ); else puts ("Wrong!!" ); return 0 ; }
? 这还真是 flag
0x04 lucknum ELF 64bit obj. Shared obj file
main( ) 1 2 3 4 5 6 7 8 9 10 11 12 13 int __fastcall main (int argc, const char **argv, const char **envp) { int v4; char s[48 ]; strcpy (s, "flag{c0ngr@tul@ti0n_f0r_luck_numb3r}" ); v4 = 0 ; __isoc99_scanf(&unk_2004, &v4); if ( v4 == 7 ) return puts (s); else return puts ("sorry!" ); }
不是 哥们 ..
0x05 reverse_re3 64 位 无壳
main( ) 1 2 3 4 5 6 7 8 9 10 __int64 __fastcall main (__int64 a1, char **a2, char **a3) { int v4; sub_11B4(a1, a2, a3); do v4 = sub_940(); while ( v4 != 1 && v4 != -1 ); return 0LL ; }
sub_940( ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 __int64 sub_940 () { int v0; int v2; int v3; char v4[520 ]; unsigned __int64 v5; v5 = __readfsqword(0x28 u); v3 = 0 ; memset (v4, 0 , 0x200 uLL); _isoc99_scanf(&unk_1278, v4, v4); while ( 1 ) { do { v2 = 0 ; sub_86C(); v0 = v4[v3]; if ( v0 == 100 ) { v2 = sub_E23(); } else if ( v0 > 100 ) { if ( v0 == 115 ) { v2 = sub_C5A(); } else if ( v0 == 119 ) { v2 = sub_A92(); } } else { if ( v0 == 27 ) return 0xFFFFFFFF LL; if ( v0 == 97 ) v2 = sub_FEC(); } ++v3; } while ( v2 != 1 ); if ( dword_202AB0 == 2 ) break ; ++dword_202AB0; } puts ("success! the flag is flag{md5(your input)}" ); return 1LL ; }
其中 w a s d = 119 97 115 100 因此 (在 F5 反编译的伪代码里面单击按”R” 就可以快捷更换成 ASCII==>字符 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 sub_940(){ while ( 1 ){do { if ( v0 == 'd' ) { v2 = sub_E23(); } else if ( v0 > 'd' ) { if ( v0 == 's' ) { v2 = sub_C5A(); } else if ( v0 == 'w' ) { v2 = sub_A92(); } } else { if ( v0 == 27 ) return 0xFFFFFFFF LL; if ( v0 == 'a' ) v2 = sub_FEC(); } ++v3; } while ( v2 != 1 ); if ( dword_202AB0 == 2 ) break ; ++dword_202AB0; } return 1LL ; }
因此这是一个操控 wasd 移动的函数 研究一下移动函数 sub_E23()
sub_E23( ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 __int64 sub_E23 () { if ( dword_202AB8 != 14 ) { if ( dword_202020[225 * dword_202AB0 + 1 + 15 * dword_202AB4 + dword_202AB8] == 1 ) { dword_202020[225 * dword_202AB0 + 1 + 15 * dword_202AB4 + dword_202AB8] = 3 ; dword_202020[225 * dword_202AB0 + 15 * dword_202AB4 + dword_202AB8] = 1 ; } else if ( dword_202020[225 * dword_202AB0 + 1 + 15 * dword_202AB4 + dword_202AB8] == 4 ) { return 1LL ; } } return 0LL ; }
这里面涉及了一些东西 我替换一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sub_E23(){ if ( y != 14 ) { if ( map [225 * num + 1 + 15 * x + y] == 1 ) { map [225 * num + 1 + 15 * x + y] = 3 ; map [225 * num + 15 * x + y] = 1 ; } else if ( map [225 * num + 1 + 15 * x + y] == 4 ) { return 1LL ; } } return 0LL ; }
好看点了 那么步进这几个变量 看看意义
1 2 3 4 5 6 .data:000202020 dword_202020 dd 5 dup(1 ), 0 Ah dup (0 ) , 5 dup (1 ) , 0, 3, 2 dup (1 ) , 6 dup (0 ) .data:000202020 ; DATA XREF: sub_86C+82 ↑o .data:000202020 ; sub_A92+76 ↑o ... ......... .data:000202 A68 dd 1 , 0 Eh dup (0 ) , 4, 0 .data:000202A68 _data ends
dword_202020:map 其实就是题目给的地图,可以双击进去看看(shift+e 提取数据)
dword_202AB0:num 代表哪个迷宫,此题有 3 个迷宫(至于为什么后文会提及)
dword_202AB4:x 代表行(因为 15*,说明可能是一行 15 个数字,大胆猜测!)
dword_202AB8:y 代表列
225 = 15 * 15 大概是 15×15 的地图
dword 分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sub_E23(){ if ( y != 14 ) { if ( map [225 * num + 1 + 15 * x + y] == 1 ) { map [225 * num + 1 + 15 * x + y] = 3 ; map [225 * num + 15 * x + y] = 1 ; } else if ( map [225 * num + 1 + 15 * x + y] == 4 ) { return 1LL ; } } return 0LL ; }
y != 14
只有 15 行, 也就是最多向下位移 14 次
map[225 * num + 1 + 15 * x + y] == 1
判断当前位置右移的数字是不是 1,如果是将该位置标志为 3,之前的位置标志为 1,其实就是暗示我们 1 是可以走的,而 3 其实是我们的(起点)实际位置,如果不理解后面看看迷宫就明白了
map[225 * num + 1 + 15 * x + y] == 4
判断当前位置右移的数字是不是 4, 是 4 就 1LL 结束游戏
提醒有的题目不一定是只有上下左右四个方向(斜向), 因此可以去看看 sub_C5A() sub_FEC() 是不是也是这个思路
15 * x
说明每次走都会增加一行
(到这里我觉得大体是这样: 225 个数字连续排列, 当按照 15×15 的格式来 output 就成了一个迷宫图)
现在回到原来的函数
部分 sub_940( ) 1 2 3 4 while ( v2 != 1 );if ( dword_202AB0 == 2 ) break ; ++dword_202AB0;
这里的 dword_202AB0==2
我们在前面提到它可能是标识哪一个迷宫的,这里说 ==2
的话就 break,否则就++,说明这里会循环 3 次,说明会有 3 个迷宫,接下来我们来看看这个稍微的迷宫长什么样
步进 dword_202020 (map)
dword_202020 按 shift+e 提取数据,然后导出来 (C unsigned char array decimal)
1 2 3 4 5 6 unsigned char ida_chars[] ={ 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , ... 0 , 0 , 4 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
这里太长了 中间部分隐藏掉算了 这里 txt 里面替换掉 , 空格之类的, 只保留 01
脚本生成地图 dword 类型的数据是 4 位一组,只取第一位作为数值,也就是说 100010000111 最终会变成 110 ,后 3 位是填充的 (如果提取的是 initialized C variable 就可以避免这一步)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 input_string = input ("请输入需要处理的字符串:" ) output_string = input_string.replace("\n" , "" ) ZeK1D = output_string.replace(" " , "" ) def extract_chars (input_string ): chunks = [input_string[i:i+4 ] for i in range (0 , len (input_string), 4 )] first_chars = [chunk[0 ] for chunk in chunks if chunk] output= '' .join(first_chars) print (output) extract_chars(ZeK1D)
(这里输出之后是 3 张地图 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 // 3 是起点 111110000000000 111110311000000 111110001000000 111110001000000 111110001111100 111110000000100 111110000000100 111110000000110 111110000000010 111110000000040 111111111111111 111111111111111 111111111111111 111111111111111 111111111111111 // ddsssddddsssdss // 3 是起点 110000000000000 110311111000000 110110001000000 110000001000000 110110001111100 110110000000100 110110000000100 110110000011110 110110000010010 110110000010000 110111111010110 110111111111110 110000000000040 111111111111111 111111111111111 // dddddsssddddsssaassssddds // 3 是起点 000000000000000 031100000000000 000101110000000 000111010000000 000010010000000 011010010000000 001110010000000 000000010000000 000000011110000 000000000010000 000000000010000 000000000010000 000000000011110 000000000000010 000000000000040 // ddssddwddssssssdddssssdddss
结果 ddsssddddsssdssdddddsssddddsssaassssdddsddssddwddssssssdddssssdddss
flag 是 md5 加密的结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import hashlibdef md5_encrypt (input_string ): input_bytes = input_string.encode('utf-8' ) hash_object = hashlib.md5() hash_object.update(input_bytes) encrypted_string = hash_object.hexdigest() return encrypted_string input_str = "ddsssddddsssdssdddddsssddddsssaassssdddsddssddwddssssssdddssssdddss" encrypted_str = md5_encrypt(input_str) print (f"The MD5 encrypted string is: {encrypted_str} " )
输出 md5 为 aeea66fcac7fa80ed8f79f38ad5bb953
0x06 1000Click 无壳 x64 卧槽 这个程序这么多文件
Shift + F12 查看字符串 Ctrl + F 搜索 flag 看看 搜到了一大堆? 双击步入任意一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 .data:005 C4AEF align 10 h .data:005 C4AF0 aFlagSusvek8ywl db 'flag{SUsVEk8Ywltso}' ,0 .data:005 C4B17 align 4 .data:005 C4B18 aFlagLoa77rxsiq db 'flag{LOa77RXSIqZWC}' ,0 .data:005 C4B3F align 10 h .data:005 C4B40 aFlagSiwprwdvx7 db 'flag{SIwprwdVx7RXe}' ,0 .data:005 C4B67 align 4 .data:005 C4B68 ; CHAR Text[] .data:005 C4B68 Text db 'flag{TIBntXVbdZ4Z9}' ,0 .data:005 C4B68 ; DATA XREF: sub_402790+23 ↑o .data:005 C4B68 ; sub_4027D0:loc_40282A↑o .data:005 C4B8F align 10 h .data:005 C4B90 aFlagHilcmjfvtk db 'flag{hILCmjfvtk0hs}' ,0 .data:005 C4BB7 align 4 .data:005 C4BB8 aFlagX3rcv2cx2t db 'flag{X3rCv2cx2t18G}' ,0 .data:005 C4BDF align 10 h .data:005 C4BE0 aFlagUahcq9fz0d db 'flag{UaHcQ9fz0D8ZX}' ,0 .data:005 C4C07 align 4 .data:005 C4C08 aFlagYxvrfjabc5 db 'flag{YXvrfJAbc58tl}' ,0
发现只有一个 flag 是有数据调用的,猜测是最终的 flag
0x07 crypt
怎么有密码啊 QwQ RC4
exeinfo : x64 Microsoft Visual C++ v14.26 - 2019 - microsoft.com (exe 4883EC28-48) - no sec. Cab.7z.Zip [ Win Vista ]
PE 控制台程序
main( ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 int __fastcall main (int argc, const char **argv, const char **envp) { unsigned int v3; unsigned int v4; void *v5; void *v7; int i; void *v9; char v10[32 ]; char Str[128 ]; strcpy (Str, "12345678abcdefghijklmnopqrspxyz" ); memset (&Str[32 ], 0 , 0x60 ui64); memset (v10, 0 , 0x17 ui64); sub_1400054D0("%s" , v10); v9 = malloc (0x408 ui64); v3 = strlen (Str); sub_140001120(v9, Str, v3); v4 = strlen (v10); sub_140001240(v9, v10, v4); for ( i = 0 ; i < 22 ; ++i ) { if ( ((unsigned __int8)v10[i] ^ 0x22 ) != byte_14013B000[i] ) { v5 = (void *)sub_1400015A0(&off_14013B020, "error" ); _CallMemberFunction0(v5, sub_140001F10); return 0 ; } } v7 = (void *)sub_1400015A0(&off_14013B020, "nice job" ); _CallMemberFunction0(v7, sub_140001F10); return 0 ; }
分析 main 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 int __cdecl main (int argc, const char **argv, const char **envp) { unsigned int str_length; unsigned int myflag_length; void *v5; void *v7; int i; void *memory; char myflag[32 ]; char Str[128 ]; strcpy (Str, "12345678abcdefghijklmnopqrspxyz" ); memset (&Str[32 ], 0 , 0x60 ui64); memset (myflag, 0 , 0x17 ui64); sub_1400054D0("%s" , myflag); memory = malloc (0x408 ui64); str_length = strlen (Str); sub_140001120(memory, Str, str_length); myflag_length = strlen (myflag); sub_140001240(memory, myflag, myflag_length); for ( i = 0 ; i < 22 ; ++i ) { if ( ((unsigned __int8)myflag[i] ^ 0x22 ) != main_break[i] ) { v5 = (void *)sub_1400015A0(&off_14013B020, "error" ); _CallMemberFunction0(v5, sub_140001F10); return 0 ; } } v7 = (void *)sub_1400015A0(&off_14013B020, "nice job" ); _CallMemberFunction0(v7, sub_140001F10); return 0 ; }
((unsigned __int8)myflag[i] ^ 0x22) != main_break[i]
提取 main_break[ ]数组 (ida_chars[]) (SHITF+e)
1 2 3 4 5 6 unsigned char ida_chars[] ={ 0x9E , 0xE7 , 0x30 , 0x5F , 0xA7 , 0x01 , 0xA6 , 0x53 , 0x59 , 0x1B ,0x0A , 0x20 , 0xF1 , 0x73 , 0xD1 , 0x0E , 0xAB , 0x09 , 0x84 , 0x0E ,0x8D , 0x2B , 0x00 , 0x00 };
sub_140001120( ) re4_init( )函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 sub_140001120(memory, Str, str_length); __int64 __fastcall sub_140001120 (_DWORD *a1, __int64 a2, int a3) { __int64 result; int i; int j; int v6; int v7; int v8; _DWORD *v9; *a1 = 0 ; a1[1 ] = 0 ; v9 = a1 + 2 ; for ( i = 0 ; i < 256 ; ++i ) v9[i] = i; v6 = 0 ; result = 0 i64; LOBYTE(v7) = 0 ; for ( j = 0 ; j < 256 ; ++j ) { v8 = v9[j]; v7 = (unsigned __int8)(*(_BYTE *)(a2 + v6) + v8 + v7); v9[j] = v9[v7]; v9[v7] = v8; if ( ++v6 >= a3 ) v6 = 0 ; result = (unsigned int )(j + 1 ); } return result; }
这段代码看起来是实现了一种称为 RC4 算法(也称为 ARC4)的流密码算法,用于加密和解密数据。让我们逐步分析它:
函数调用 c 复制代码sub_140001120(memory, Str, str_length);
这是函数调用,传递了三个参数:
memory
:可能是一个指向缓冲区的指针,用于存储加密后的结果。
Str
:一个指向数据的指针,这里用 a2
表示,通常是待加密或解密的数据。
str_length
:数据的长度,这里用 a3
表示,表示数据的字节数。
函数定义分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 __int64 __fastcall sub_140001120 (_DWORD *a1, __int64 a2, int a3) { __int64 result; int i; int j; int v6; int v7; int v8; _DWORD *v9; *a1 = 0 ; a1[1 ] = 0 ; v9 = a1 + 2 ; for ( i = 0 ; i < 256 ; ++i ) v9[i] = i; v6 = 0 ; result = 0 i64; LOBYTE(v7) = 0 ; for ( j = 0 ; j < 256 ; ++j ) { v8 = v9[j]; v7 = (unsigned __int8)(*(_BYTE *)(a2 + v6) + v8 + v7); v9[j] = v9[v7]; v9[v7] = v8; if ( ++v6 >= a3 ) v6 = 0 ; result = (unsigned int )(j + 1 ); } return result; }
分析解释
S 盒初始化 :
a1
是一个指向 _DWORD
类型的指针,用于存储 RC4 算法中的 S 盒。
*a1 = 0;
和 a1[1] = 0;
初始化了 S 盒的前两个位置为 0。
v9 = a1 + 2;
将 v9
指向 S 盒的起始地址(第三个位置)。
S 盒初始化 :
使用一个简单的循环将 S 盒中的值初始化为 [0, 1, 2, ..., 255]
。
核心循环 :
使用两个循环变量 j
和 v6
对 S 盒进行操作。
v8 = v9[j];
获取 S 盒中的一个值。
v7 = (unsigned __int8)(*(_BYTE *)(a2 + v6) + v8 + v7);
计算一个临时变量 v7
,其中 a2
是数据的起始地址,v6
是数据的当前索引。
v9[j] = v9[v7];
和 v9[v7] = v8;
交换 S 盒中的两个值,根据计算得到的 v7
。
if ( ++v6 >= a3 ) v6 = 0;
更新数据索引 v6
,如果超过数据长度 a3
则重新开始。
result = (unsigned int)(j + 1);
更新返回值。
总结 这段代码实现了 RC4 算法的主要部分,用于生成一个伪随机的 S 盒,并对数据进行加密或解密。具体的加密和解密过程需要结合其他代码来完整实现。 我们的 key 是 传入的 str = "12345678abcdefghijklmnopqrspxyz"
sub_140001240( ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 _DWORD *__fastcall sub_140001240 (_DWORD *a1, __int64 a2, int a3) { _DWORD *result; int i; int v5; int v6; int v7; int v8; _DWORD *v9; v5 = *a1; v6 = a1[1 ]; v9 = a1 + 2 ; for ( i = 0 ; i < a3; ++i ) { v5 = (unsigned __int8)(v5 + 1 ); v7 = v9[v5]; v6 = (unsigned __int8)(v7 + v6); v8 = v9[v6]; v9[v5] = v8; v9[v6] = v7; *(_BYTE *)(a2 + i) ^= LOBYTE(v9[(unsigned __int8)(v8 + v7)]); } *a1 = v5; result = a1; a1[1 ] = v6; return result; }
这段代码实现了 RC4 算法的一部分,用于对数据进行解密或解码。让我们逐步分析它:
函数定义分析 c 复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 _DWORD *__fastcall sub_140001240 (_DWORD *a1, __int64 a2, int a3) { _DWORD *result; int i; int v5; int v6; int v7; int v8; _DWORD *v9; v5 = *a1; v6 = a1[1 ]; v9 = a1 + 2 ; for (i = 0 ; i < a3; ++i) { v5 = (unsigned __int8)(v5 + 1 ); v7 = v9[v5]; v6 = (unsigned __int8)(v7 + v6); v8 = v9[v6]; v9[v5] = v8; v9[v6] = v7; *(_BYTE *)(a2 + i) ^= LOBYTE(v9[(unsigned __int8)(v8 + v7)]); } *a1 = v5; result = a1; a1[1 ] = v6; return result; }
分析解释
变量初始化 :
v5
和 v6
分别从 a1
中读取初始状态,这可能是前一个使用 RC4 算法加密时保存的状态。
v9
是指向 RC4 算法的 S 盒的指针,从 a1 + 2
开始。
RC4 解密核心循环 :
for
循环对每个字节进行解密操作,循环次数由 a3
决定,a3
是数据的长度。
v5 = (unsigned __int8)(v5 + 1);
和 v6 = (unsigned __int8)(v7 + v6);
分别用来更新 v5
和 v6
。
v7 = v9[v5];
和 v8 = v9[v6];
从 S 盒中取出两个值 v7
和 v8
。
v9[v5] = v8;
和 v9[v6] = v7;
交换 S 盒中的两个值。
*(_BYTE *)(a2 + i) ^= LOBYTE(v9[(unsigned __int8)(v8 + v7)]);
对数据进行解密并与原始数据异或,a2
是数据的起始地址。
状态更新 :
*a1 = v5;
和 a1[1] = v6;
更新 a1
中的状态,以便下次使用时能继续正确解密数据。
总结 这段代码实现了 RC4 算法的解密过程,用来解密通过相同的密钥加密的数据。它通过交换 S 盒中的元素和对数据的异或操作来逆转加密过程,恢复原始数据。
解密 RC4 加密算法的原理及实现_叙述 rc4 原理以及过程-CSDN 博客
分析 main 函数得知: 加密之后的 myflag[i]^0x22=ida_chars[i] 也就是
myflag[i]=ida_chars[i]^0x22` 因此可以得到密文
1 2 3 4 5 6 7 encode_flag=[] ida_chars=[0x9E , 0xE7 , 0x30 , 0x5F , 0xA7 , 0x01 , 0xA6 , 0x53 , 0x59 , 0x1B ,0x0A , 0x20 , 0xF1 , 0x73 , 0xD1 , 0x0E , 0xAB , 0x09 , 0x84 , 0x0E ,0x8D , 0x2B , 0x00 , 0x00 ] for i in range (len (ida_chars)): encode_flag.append(ida_chars[i]^0x22 ) print (encode_flag)
因此有了 encodeflag 跟 key
1 2 3 encode_flag = [188 , 197 , 18 , 125 , 133 , 35 , 132 , 113 , 123 , 57 , 40 , 2 , 211 , 81 , 243 , 44 , 137 , 43 , 166 , 44 , 175 , 9 , 34 , 34 ] key = "12345678abcdefghijklmnopqrspxyz"
同时:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #include <stdio.h> #include <string.h> typedef unsigned longULONG;void rc4_init (unsigned char *s, unsigned char *key, unsigned long Len) { int i = 0 , j = 0 ; char k[256 ] = {0 }; unsigned char tmp = 0 ; for (i = 0 ; i < 256 ; i++) { s[i] = i; k[i] = key[i % Len]; } for (i = 0 ; i < 256 ; i++) { j = (j + s[i] + k[i]) % 256 ; tmp = s[i]; s[i] = s[j]; s[j] = tmp; } } void rc4_crypt (unsigned char *s, unsigned char *Data, unsigned long Len) { int i = 0 , j = 0 , t = 0 ; unsigned long k = 0 ; unsigned char tmp; for (k = 0 ; k < Len; k++) { i = (i + 1 ) % 256 ; j = (j + s[i]) % 256 ; tmp = s[i]; s[i] = s[j]; s[j] = tmp; t = (s[i] + s[j]) % 256 ; Data[k] ^= s[t]; } } int main () { unsigned char s[256 ] = {0 }, s2[256 ] = {0 }; char key[256 ] = {"12345678abcdefghijklmnopqrspxyz" }; char pData[] = {0xbc , 0xc5 , 0x12 , 0x7d , 0x85 , 0x23 , 0x84 , 0x71 , 0x7b , 0x39 , 0x28 , 0x2 , 0xd3 , 0x51 , 0xf3 , 0x2c , 0x89 , 0x2b , 0xa6 , 0x2c , 0xaf , 0x9 , 0x22 , 0x22 }; unsigned long len = strlen (pData); int i; printf ("pData=%s\n" , pData); printf ("key=%s,length=%d\n\n" , key, strlen (key)); rc4_init(s, (unsigned char *)key, strlen (key)); printf ("\n\n" ); for (i = 0 ; i < 256 ; i++) { s2[i] = s[i]; } printf ("已经加密,现在解密:\n\n" ); rc4_crypt(s2, (unsigned char *)pData, len); printf ("pData=%s\n\n" , pData); return 0 ; } # 解密方法
pData=flag{nice_to_meet_you}nm
Re+Crypto 对我还是太上强度了点 (