re ak,除了最后的LittleJunk对我来说有点意义,另外两题都很简单,就写一下LittleJunk的wp
LittleJunk
程序加了花指令,没法正常F5
去除花指令后(见常见花指令识别与解决方案)

调用loc_404000
之前进行了SMC自解密,所以静态分析时loc_404000
并不能正常识别为函数

动态调试起来分析,U,C配合把自解密的ByteCode转成汇编,按P

去除花指令后
void __stdcall sub_9F4000(__int64 *key)
{
int *v1; // [esp+8h] [ebp-48h]
__int64 v2; // [esp+Ch] [ebp-44h]
int i; // [esp+14h] [ebp-3Ch]
int v4; // [esp+18h] [ebp-38h]
unsigned __int64 v5[6]; // [esp+1Ch] [ebp-34h] BYREF
sub_9F1A60(); // printf("flag plz:");
sub_9F1A80(); // 首尾匹配 flag{xxx} 限定长度
v4 = 0;
smcDecrypt2();
v1 = RC4Encrypt(); // RC4加密中括号内的内容 即flag{xxx} -> xxx
v2 = 0i64;
for ( i = 0; i < 32; ++i )
{
v2 = (v2 << 8) + v1[i];
if ( !((i + 1) % 8) )
{
LODWORD(v5[v4]) = v2;
HIDWORD(v5[v4++]) = HIDWORD(v2);
v2 = 0i64;
}
} // 转换为QWORD
sub_9F1660(v5, key); // tea加密
}
这题用的都是魔改过的算法
首先是flag中括号内的32位字符串进行魔改RC4加密,而后将密文转换为QWORD,使用魔改TEA算法加密,与结果比对
// RC4
int *sub_9F5000()
{
int v1[600]; // [esp+0h] [ebp-988h]
int v2; // [esp+960h] [ebp-28h]
int v3; // [esp+964h] [ebp-24h]
int i; // [esp+968h] [ebp-20h]
int k; // [esp+96Ch] [ebp-1Ch]
int v6; // [esp+970h] [ebp-18h]
int j; // [esp+974h] [ebp-14h]
char v8[12]; // [esp+978h] [ebp-10h] BYREF
for ( i = 0; i < 32; ++i )
dword_9F8460[i] = byte_9F8430[i]; // byte_9F8430 存放flag{xx} -> xx
strcpy(v8, "dasctf:3"); // key
v6 = 0;
v3 = 0;
for ( j = 0; j < 256; ++j )
{
v1[j + 300] = j;
v1[j] = v8[j % 8];
}
v6 = 0;
for ( j = 0; j < 256; ++j )
{
v6 = (v1[j] + v1[j + 300] + v6) % 256;
v2 = v1[j + 300];
v1[j + 300] = v1[v6 + 300];
v1[v6 + 300] = v2;
}
j = 0;
v6 = 0;
v3 = 0;
for ( k = 0; k < 32; ++k )
{
j = (j + 1) % 256;
v6 = (v1[j + 300] + v6) % 256;
v1[j + 300] = v1[v6 + 300] & ~v1[j + 300] | v1[j + 300] & ~v1[v6 + 300];
v1[v6 + 300] = v1[v6 + 300] & ~v1[j + 300] | v1[j + 300] & ~v1[v6 + 300];
v1[j + 300] = v1[v6 + 300] & ~v1[j + 300] | v1[j + 300] & ~v1[v6 + 300];
v3 = (v1[v6 + 300] + v1[j + 300]) % 256;
dword_9F8460[k] ^= v1[k + 300];
}
return dword_9F8460;
}
与标准RC4相比,修改点在于dword_9F8460[k] ^= v1[k + 300];
,具体而言在于其直接使用sbox顺序进行异或,跳过了v3 = (s[v6] + s[j]) % 256;

// TEA
void __cdecl sub_9F1660(unsigned __int64 *value, __int64 *key)
{
__int64 v2; // [esp+18h] [ebp-8Ch]
__int64 v3; // [esp+20h] [ebp-84h]
__int64 v4; // [esp+2Ch] [ebp-78h]
__int64 v5; // [esp+34h] [ebp-70h]
unsigned __int64 i; // [esp+3Ch] [ebp-68h]
int j; // [esp+44h] [ebp-60h]
__int64 v8; // [esp+48h] [ebp-5Ch]
unsigned __int64 v9; // [esp+50h] [ebp-54h]
unsigned __int64 v10; // [esp+58h] [ebp-4Ch]
unsigned __int64 v11; // [esp+60h] [ebp-44h]
unsigned __int64 v12; // [esp+68h] [ebp-3Ch]
QWORD v13[4]; // [esp+70h] [ebp-34h]
int v14; // [esp+90h] [ebp-14h]
int v15; // [esp+94h] [ebp-10h]
int v16; // [esp+98h] [ebp-Ch]
int v17; // [esp+9Ch] [ebp-8h]
v13[0] = 0xE990A522BE80F786ui64;
v13[1] = 0x8B836286B8A5EB59ui64;
v13[2] = 0x2FDE61CCEFC70FF8i64;
v13[3] = 0x56BC19E119C8B07Bi64;
v14 = 0;
v15 = 0;
v16 = 0;
v17 = 0;
v11 = *value;
v9 = value[1];
v10 = value[2];
v12 = value[3];
v8 = 0i64;
v5 = *key;
v2 = key[1];
v4 = key[2];
v3 = key[3];
for ( i = 0i64; i < 32; ++i )
{
v8 += 0x9E3779B9i64;
v11 += (v2 + (v9 >> 5)) ^ (v8 + v9) ^ (v5 + 16 * v9);
v9 += (v3 + (v11 >> 5)) ^ (v8 + v11) ^ (v4 + 16 * v11);
v10 += (v2 + (v12 >> 5)) ^ (v8 + v12) ^ (v5 + 16 * v12);
v12 += (v3 + (v10 >> 5)) ^ (v8 + v10) ^ (v4 + 16 * v10);
}
*value = v11;
value[1] = v9;
value[2] = v10;
value[3] = v12;
for ( j = 0; j < 4; ++j )
{
if ( value[j] != __PAIR64__(HIDWORD(v13[j]), v13[j]) )
{
sub_9F2A80(std::cout, "worry");
exit(0);
}
}
sub_9F2A80(std::cout, "ttttttttttql!!!");
}
TEA算法在这里魔改了变量的类型。
先写脚本解tea,(tea算法的key通过动态调试dump)
#include<stdio.h>
#include<stdint.h>
#include<windows.h>
void __cdecl decrypt(unsigned __int64 *value, __int64 *a2)
{
__int64 v2; // [esp+18h] [ebp-8Ch]
__int64 v3; // [esp+20h] [ebp-84h]
__int64 v4; // [esp+2Ch] [ebp-78h]
__int64 v5; // [esp+34h] [ebp-70h]
unsigned __int64 i; // [esp+3Ch] [ebp-68h]
__int64 v8; // [esp+48h] [ebp-5Ch]
unsigned __int64 v9; // [esp+50h] [ebp-54h]
unsigned __int64 v10; // [esp+58h] [ebp-4Ch]
unsigned __int64 v11; // [esp+60h] [ebp-44h]
unsigned __int64 v12; // [esp+68h] [ebp-3Ch]
v11 = *value;
v9 = value[1];
v10 = value[2];
v12 = value[3];
v8 = 0x13c6ef3720;
v5 = *a2;
v2 = a2[1];
v4 = a2[2];
v3 = a2[3];
for ( i = 0i64; i < 32; ++i )
{
v12 -= (v3 + (v10 >> 5)) ^ (v8 + v10) ^ (v4 + 16 * v10);
v10 -= (v2 + (v12 >> 5)) ^ (v8 + v12) ^ (v5 + 16 * v12);
v9 -= (v3 + (v11 >> 5)) ^ (v8 + v11) ^ (v4 + 16 * v11);
v11 -= (v2 + (v9 >> 5)) ^ (v8 + v9) ^ (v5 + 16 * v9);
v8 -= 0x9E3779B9i64;
}
*value = v11;
value[1] = v9;
value[2] = v10;
value[3] = v12;
}
int main(){
uint64_t v[4] = {
0xE990A522BE80F786, 0x8B836286B8A5EB59, 0x2FDE61CCEFC70FF8, 0x56BC19E119C8B07B
};
int64_t key[4] = {
0x54466076484C5476, 0x4550504F765F4344, 0x5A796F755F6D6179, 0x5F6E6565645F7468
};
decrypt(v, key);
printf("%016llx %016llx %016llx %016llx", v[0], v[1], v[2], v[3]);
return 0;
}
解得505a4cc462489e80 03aef16b785c7501 343057844ff5acb8 09616159f51713f3
写个IDAPython带回魔改的RC4函数加密前
# -*- coding:utf-8 -*-
"""
@Author: Mas0n
@File: ida_quick_script.py
@Time: 2021-08-30 16:41
@Desc: It's all about getting better.
"""
addr = 0x009F8430 # patch address
test = "505a4cc462489e80 03aef16b785c7501 343057844ff5acb8 09616159f51713f3" # patch hex data
ps = [i for i in b''.fromhex(test)]
for i, v in enumerate(ps):
ida_bytes.patch_byte(addr+i, v)
dump出dword_9F8460

python跑一下
# -*- coding:utf-8 -*-
"""
@Author: Mas0n
@File: dizzy.py
@Time: 2021-08-30 17:03
@Desc: It's all about getting better.
"""
import struct
arr = [0x00000034, 0x00000061, 0x00000035, 0xFFFFFF63, 0x00000030, 0x00000066, 0xFFFFFF31, 0xFFFFFF62, 0x00000035, 0xFFFFFF63, 0xFFFFFF63, 0x00000037, 0x00000066, 0x00000036, 0x00000030, 0x00000065, 0x00000039, 0x00000031, 0x00000038, 0xFFFFFF36, 0x00000031, 0xFFFFFF31, 0xFFFFFF37, 0xFFFFFF32, 0x00000031, 0x00000063, 0x00000038, 0x00000037, 0xFFFFFF62, 0x00000061, 0x00000030, 0xFFFFFF37, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000]
stt = ''
for i in arr:
stt += chr(i & 0xff)
print(stt)
当然如果你了解魔改点,也可以一把梭解密
#include<stdio.h>
#include<stdint.h>
#include<windows.h>
void __cdecl decrypt(unsigned __int64 *value, __int64 *a2)
{
__int64 v2; // [esp+18h] [ebp-8Ch]
__int64 v3; // [esp+20h] [ebp-84h]
__int64 v4; // [esp+2Ch] [ebp-78h]
__int64 v5; // [esp+34h] [ebp-70h]
unsigned __int64 i; // [esp+3Ch] [ebp-68h]
__int64 v8; // [esp+48h] [ebp-5Ch]
unsigned __int64 v9; // [esp+50h] [ebp-54h]
unsigned __int64 v10; // [esp+58h] [ebp-4Ch]
unsigned __int64 v11; // [esp+60h] [ebp-44h]
unsigned __int64 v12; // [esp+68h] [ebp-3Ch]
v11 = *value;
v9 = value[1];
v10 = value[2];
v12 = value[3];
v8 = 0x13c6ef3720;
v5 = *a2;
v2 = a2[1];
v4 = a2[2];
v3 = a2[3];
for ( i = 0i64; i < 32; ++i )
{
v12 -= (v3 + (v10 >> 5)) ^ (v8 + v10) ^ (v4 + 16 * v10);
v10 -= (v2 + (v12 >> 5)) ^ (v8 + v12) ^ (v5 + 16 * v12);
v9 -= (v3 + (v11 >> 5)) ^ (v8 + v11) ^ (v4 + 16 * v11);
v11 -= (v2 + (v9 >> 5)) ^ (v8 + v9) ^ (v5 + 16 * v9);
v8 -= 0x9E3779B9i64;
}
*value = v11;
value[1] = v9;
value[2] = v10;
value[3] = v12;
}
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[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[x]和s[y]
s[j] = tmp;
t=(s[i]+s[j])%256;
// Data[k] ^= s[t];
Data[k] ^= s[k]; // 魔改点
}
}
void Qword2BytesLittle(unsigned char* b, uint64_t v) {
for (int i = 0; i < 8; ++i) {
b[7 - i] = v & 0xff;
v >>= 8;
}
}
int main(){
uint64_t v[4] = {
0xE990A522BE80F786, 0x8B836286B8A5EB59, 0x2FDE61CCEFC70FF8, 0x56BC19E119C8B07B
};
int64_t key[4] = {
0x54466076484C5476, 0x4550504F765F4344, 0x5A796F755F6D6179, 0x5F6E6565645F7468
};
decrypt(v, key);
printf("TEADecrypt: %016llx %016llx %016llx %016llx\n", v[0], v[1], v[2], v[3]);
unsigned char encData[33] = {0};
for (int i = 0; i < 4; ++i) {
Qword2BytesLittle(&encData[8*i], v[i]);
}
unsigned char sbox[256];
unsigned char rc4Key[] = "dasctf:3";
rc4_init(sbox,rc4Key, strlen((char*)rc4Key));
rc4_crypt(sbox, encData, 32);
printf("flag{%s}\n", encData);
return 0;
}
这题考点主要在于对花指令的识别和处理。