采一朵花,送给艾达(2)
程序主函数中有花:
asm
.text:000000014000198F call free
.text:0000000140001994 mov eax, 1BF52h
.text:0000000140001999
.text:0000000140001999 loc_140001999: ; CODE XREF: main+9C↓j
.text:0000000140001999 jmp loc_140001AF0
.text:000000014000199E loc_14000199E: ; CODE XREF: main+67↑j
.text:000000014000199E xor eax, eax
.text:00000001400019A0 jz short near ptr loc_1400019A4+1
.text:00000001400019A2 jnz short near ptr loc_1400019A4+1
.text:00000001400019A4
.text:00000001400019A4 loc_1400019A4: ; CODE XREF: main+93↑j
.text:00000001400019A4 ; main+95↑j
.text:00000001400019A4 call near ptr 0CA5CD1F1h
.text:00000001400019A9 loope near ptr loc_140001999+1
.text:00000001400019AB lock cmp ah, [rdi+48h]
.text:00000001400019B0 mov [rbp+500h+var_560], eax
.text:00000001400019B3 mov rax, 0DCBAFF24A65D456hA4位置取消定义A5位置重定义,反编译:
cpp
int __fastcall main(int argc, const char **argv, const char **envp)
{
_main(*(_QWORD *)&argc, argv, envp);
printf(&Format);
*(_QWORD *)&Size[1] = malloc(0x10000u);
scanf("%s", *(_QWORD *)&Size[1]);
Size[0] = strlen(*(const char **)&Size[1]);
if ( Size[0] == 40 )
{
v4[0] = 0x673AF04AEFE18A5CLL;
v4[1] = 0xDCBAFF24A65D456LL;
v4[2] = 0xCFD8B1539076E546uLL;
v4[3] = 0xFD469B79EF8A33B7uLL;
v4[4] = 0x5985D24E20980BECLL;
v8 = (char *)KeyGen();
v7 = strlen(v8);
rc4_init(v5, v8, v7);
memcpy(v6, *(const void **)&Size[1], Size[0]);
rc4_crypt(v5, v6, Size[0]);
for ( i = 0; i < Size[0]; ++i )
{
if ( v6[i] != *((_BYTE *)v4 + i) )
{
printf(&Format_);
free(*(void **)&Size[1]);
return 0;
}
}
printf(&Format__0);
free(*(void **)&Size[1]);
return 0;
}
else
{
puts(&Buffer);
free(*(void **)&Size[1]);
return 114514;
}
}Keygen中有类似的花,去除后反编译:
cpp
const char *KeyGen()
{
malloc(0x11u);
return "PickingUpFlowers";
}查看RC4init:
cpp
__int64 rc4_init()
{
v6 = 0;
strcpy(Destination, "Wow! Why this function looks empty???");
v4 = 0;
memset(buf_, 0, sizeof(buf_));
strcpy(Source, "Not all kinds of the junk codes will make IDA fail analyze and dispaly JUMPOUT.");
strcpy(
Try_to_use_TAB_to_switch_to_the_assembly_page_and_find_out_what,
"Try to use TAB to switch to the assembly page and find out what happened to this function.");
strcat(Destination, Source);
strcat(Destination, Try_to_use_TAB_to_switch_to_the_assembly_page_and_find_out_what);
return 0;
}发现函数几乎是空的,没有重要逻辑,也没有jumpout,但是提示要查看汇编:
asm
.text:0000000140001621 call strcat
.text:0000000140001626 push rax
.text:0000000140001627 xor rax, rax
.text:000000014000162A xor rax, 17h
.text:000000014000162E sub rax, 10h
.text:0000000140001632 call $+5
.text:0000000140001637
.text:0000000140001637 label_of_flower:
.text:0000000140001637 add rax, 0Dh
.text:000000014000163B xor rax, 0
.text:000000014000163F and rax, 7
.text:0000000140001643 and rax, 21h
.text:0000000140001647 cmp rax, 1
.text:000000014000164B jz short label_continue_to_normal_code
.text:000000014000164D retn
.text:000000014000164E ; ---------------------------------------------------------------------------
.text:000000014000164E
.text:000000014000164E label_continue_to_normal_code: ; CODE XREF: rc4_init+1FB↑j
.text:000000014000164E pop rax
.text:000000014000164F mov [rbp+170h+var_14], 0
.text:0000000140001659 jmp short loc_140001683发现了call $+5和retn,符号表也给出了这里正常代码的恢复位置,将call $+5到retn的位置全部nop即可
cpp
char *__fastcall rc4_init(unsigned __int8 *a1, unsigned __int8 *a2, int a3)
{
v10 = 0;
strcpy(Destination, "Wow! Why this function looks empty???");
v7 = 0;
memset(buf_, 0, sizeof(buf_));
strcpy(Source, "Not all kinds of the junk codes will make IDA fail analyze and dispaly JUMPOUT.");
strcpy(
Try_to_use_TAB_to_switch_to_the_assembly_page_and_find_out_what,
"Try to use TAB to switch to the assembly page and find out what happened to this function.");
strcat(Destination, Source);
result = strcat(Destination, Try_to_use_TAB_to_switch_to_the_assembly_page_and_find_out_what);
for ( i = 0; i <= 255; ++i )
{
result = (char *)&a1[i];
*result = i ^ 0xCC;
}
for ( i = 0; i <= 255; ++i )
{
v10 = (a1[i] + v10 + a2[i % a3]) % 256;
v9 = a1[i];
a1[i] = a1[v10];
result = (char *)v9;
a1[v10] = v9;
}
return result;
}发现和正常的RC4_KSA相比略有魔改,PRGA函数也有类似之前的两个花,去除即可:
cpp
void __fastcall rc4_crypt(unsigned __int8 *a1, _BYTE *a2, __int64 Size)
{
v7 = 0;
v6 = 0;
for ( Size_1 = 0; Size_1 < (int)Size; ++Size_1 )
{
v7 = (v7 + 1) % 256;
v6 = (a1[v7] + v6) % 256;
v3 = a1[v7];
a1[v7] = a1[v6];
a1[v6] = v3;
a2[Size_1] ^= a1[(unsigned __int8)(a1[v7] + a1[v6])];
}
for ( Size_2 = 0; Size_2 < (int)Size; ++Size_2 )
a2[Size_2] += Size_2;
}尾部多了一个加索引,解密时前置即可
编写解密脚本:
py
def rc4(key, ciphertext):
temp = bytearray()
for i, b in enumerate(ciphertext):
temp.append((b - i) % 256)
S = list(range(256))
for i in range(256):
S[i] ^= 0xCC
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
i = j = 0
plaintext = bytearray()
for char in temp:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
t = (S[i] + S[j]) % 256
plaintext.append(char ^ S[t])
return bytes(plaintext)
enc = bytearray.fromhex("5c8ae1ef4af03a6756d4654af2afcb0d46e5769053b1d8cfb7338aef799b46fdec0b98204ed28559")
key = b"PickingUpFlowers"
dec = rc4(key, enc)
print(dec)flag{WO0o0O0w_So0Oo0o_m4Ny_F1oO0o0oW3R5}