WDCTF2024 初赛 Reverse
REVERSE01
小明给出了一个程序包,作为逆向工程师的你,能否对其进行逆向分析,找出小明藏在其中的秘密?
APK内就是一个简单的调用native,然后我们拿出x86的so开始分析
导出函数没有JAVA_xxx_check,说明可能是动态注册,导入jni.h后修复一下JNI_Onload
观察RegisterNative的(const JNINativeMethod *)off_2D50,第三个即为注册地址
第一个函数是
__int64 __fastcall sm4_keyExpand(_DWORD *a1)
{
unsigned __int32 v1; // r11d
unsigned __int32 v2; // r14d
int v3; // r15d
unsigned int v4; // ecx
__int64 i; // rdx
unsigned __int32 v6; // r10d
unsigned int v7; // ebx
__int64 v8; // rbp
__int64 v9; // rsi
__int64 result; // rax
int v11; // ebx
int v12; // ebx
unsigned __int64 v13; // rt0
qword_3018 = 'Z0099864';
*a1 = 1;
v1 = _byteswap_ulong(dword_3010) ^ 0xA3B1BAC6;
v2 = _byteswap_ulong(dword_3014) ^ 0x56AA3350;
v3 = 0x534BA9AE;
v4 = 0x8B401286;
for ( i = 0LL; i != 32; ++i )
{
v6 = v2;
v2 = v3;
v3 = v4;
v7 = *(_DWORD *)((char *)&unk_CE0 + i * 4) ^ v6 ^ v2 ^ v4 ^ 7;
v8 = BYTE1(v7);
v9 = (unsigned __int8)v7;
result = (unsigned __int8)(byte_D60[HIBYTE(v7)] ^ 7) << 24;
v11 = result | ((byte_D60[BYTE2(v7)] ^ 7) << 16);
LODWORD(v8) = v11 | ((byte_D60[v8] ^ 7) << 8);
LODWORD(v13) = v11;
HIDWORD(v13) = v8 | byte_D60[v9] ^ 7;
v12 = v13 >> 19;
LODWORD(v13) = v8;
v4 = (v13 >> 9) ^ v12 ^ v1 ^ HIDWORD(v13);
a1[i + 1] = v4;
v1 = v6;
}
return result;
}
byte_D60是SM4-Box ^ 7的结果,0xA3B1BAC6和0x56AA3350均为SM4特征值。
下面就是SM4加密过程了,16个字节为一组的ECB加密
unsigned __int64 __fastcall SM4_Encrypt(__int64 a1, unsigned __int8 *a2, _BYTE *a3)
{
__m128i v3; // xmm0
__int64 i; // r9
unsigned int v5; // ecx
unsigned int v6; // ebx
int v7; // esi
int v8; // eax
int v9; // ecx
int v10; // esi
unsigned __int64 v11; // rt0
unsigned int v12; // esi
int v13; // eax
int v14; // eax
int v15; // eax
int v16; // eax
_OWORD v18[7]; // [rsp+10h] [rbp-98h] BYREF
__int128 v19; // [rsp+80h] [rbp-28h]
unsigned __int64 v20; // [rsp+90h] [rbp-18h]
v20 = __readfsqword(0x28u);
v19 = 0LL;
memset(v18, 0, sizeof(v18));
v3 = _mm_or_si128(
_mm_or_si128(
_mm_cvtepu8_epi32(_mm_insert_epi8(_mm_insert_epi8(_mm_insert_epi8(_mm_cvtsi32_si128(a2[15]), a2[11], 1), a2[7], 2), a2[3], 3)),
_mm_slli_epi32(
_mm_cvtepu8_epi32(
_mm_insert_epi8(
_mm_insert_epi8(_mm_insert_epi8(_mm_cvtsi32_si128(a2[14]), a2[10], 1), a2[6], 2),
a2[2],
3)),
8u)),
_mm_or_si128(
_mm_slli_epi32(
_mm_cvtepu8_epi32(
_mm_insert_epi8(
_mm_insert_epi8(_mm_insert_epi8(_mm_cvtsi32_si128(a2[13]), a2[9], 1), a2[5], 2),
a2[1],
3)),
0x10u),
_mm_slli_epi32(
_mm_cvtepu8_epi32(_mm_insert_epi8(_mm_insert_epi8(_mm_insert_epi8(_mm_cvtsi32_si128(a2[12]), a2[8], 1), a2[4], 2), *a2, 3)),
0x18u)));
for ( i = 0LL; i != 32; ++i )
{
v5 = *(_DWORD *)(a1 + 4 * i) ^ _mm_extract_epi32(v3, 1) ^ _mm_extract_epi32(v3, 2) ^ _mm_cvtsi128_si32(v3);
v6 = byte_D60[HIBYTE(v5)] ^ 7;
` v7 = (v6 << 24) | ((byte_D60[BYTE2(v5)] ^ 7) << 16);
v8 = v7 | ((byte_D60[BYTE1(v5)] ^ 7) << 8);
v9 = byte_D60[(unsigned __int8)v5] ^ 7;
LODWORD(v11) = v7;
HIDWORD(v11) = v8 + v9;
v10 = v11 >> 22;
HIDWORD(v11) = v8 + v9;
LODWORD(v11) = v8;
v12 = (v11 >> 14) ^ (__PAIR64__(v9, v8) >> 8) ^ (v8 + v9) ^ _mm_extract_epi32(v3, 3) ^ ((v6 >> 6) + 4 * (v8 + v9)) ^ v10;
*((_DWORD *)v18 + i) = v12;
v3 = _mm_blend_epi16(_mm_shuffle_epi32(v3, 144), _mm_cvtsi32_si128(v12), 3);
}
v13 = HIDWORD(v19);
*a3 = HIBYTE(v19);
a3[1] = BYTE2(v13);
a3[2] = BYTE1(v13);
a3[3] = v13;
v14 = DWORD2(v19);
a3[4] = BYTE11(v19);
a3[5] = BYTE2(v14);
a3[6] = BYTE1(v14);
a3[7] = v14;
v15 = DWORD1(v19);
a3[8] = BYTE7(v19);
a3[9] = BYTE2(v15);
a3[10] = BYTE1(v15);
a3[11] = v15;
v16 = v19;
a3[12] = BYTE3(v19);
a3[13] = BYTE2(v16);
a3[14] = BYTE1(v16);
a3[15] = v16;
return __readfsqword(0x28u);
}
抄出来的东西,在这留一份
#include <Windows.h>
#include <mmintrin.h>
#include <xmmintrin.h>
#include <emmintrin.h>
#include <pmmintrin.h>
#include <tmmintrin.h>
#include <smmintrin.h>
#include <nmmintrin.h>
#include <wmmintrin.h>
#include <immintrin.h>
#include <intrin.h>
#include "def.h"
unsigned char byte_D60[] =
{
0xD1, 0x97, 0xEE, 0xF9, 0xCB, 0xE6, 0x3A, 0xB0, 0x11, 0xB1,
0x13, 0xC5, 0x2F, 0xFC, 0x2B, 0x02, 0x2C, 0x60, 0x9D, 0x71,
0x2D, 0xB9, 0x03, 0xC4, 0xAD, 0x43, 0x14, 0x21, 0x4E, 0x81,
0x01, 0x9E, 0x9B, 0x45, 0x57, 0xF3, 0x96, 0xE8, 0x9F, 0x7D,
0x34, 0x53, 0x0C, 0x44, 0xEA, 0xC8, 0xAB, 0x65, 0xE3, 0xB4,
0x1B, 0xAE, 0xCE, 0x0F, 0xEF, 0x92, 0x87, 0xD8, 0x93, 0xFD,
0x72, 0x88, 0x38, 0xA1, 0x40, 0x00, 0xA0, 0xFB, 0xF4, 0x74,
0x10, 0xBD, 0x84, 0x5E, 0x3B, 0x1E, 0xE1, 0x82, 0x48, 0xAF,
0x6F, 0x6C, 0x86, 0xB5, 0x76, 0x63, 0xDD, 0x8C, 0xFF, 0xEC,
0x08, 0x4C, 0x77, 0x51, 0x9A, 0x32, 0x19, 0x23, 0x09, 0x59,
0x64, 0x5F, 0xD6, 0xA5, 0x22, 0x25, 0x7B, 0x3C, 0x06, 0x26,
0x7F, 0x80, 0xD3, 0x07, 0x41, 0x50, 0x98, 0xD4, 0x20, 0x55,
0x4B, 0x31, 0x05, 0xE0, 0xA7, 0xC3, 0xCF, 0x99, 0xED, 0xB8,
0x8D, 0xD5, 0x47, 0xC0, 0x3F, 0xB2, 0xA4, 0xF0, 0xF5, 0xC9,
0xFE, 0x66, 0x12, 0xA6, 0xE7, 0xA9, 0x5A, 0xA3, 0x9C, 0x33,
0x1D, 0x52, 0xAA, 0x94, 0x35, 0x37, 0xF2, 0x8B, 0xB6, 0xE4,
0x1A, 0xF1, 0xE5, 0x29, 0x85, 0x61, 0xCD, 0x67, 0xC7, 0x2E,
0x24, 0xAC, 0x0A, 0x54, 0x49, 0x68, 0xD2, 0xDC, 0x30, 0x42,
0xD9, 0xFA, 0x89, 0x28, 0x04, 0xF8, 0x6D, 0x75, 0x6A, 0x6B,
0x5C, 0x56, 0x8A, 0x1C, 0xA8, 0x95, 0xBC, 0xDA, 0xBB, 0x78,
0x16, 0xDE, 0x5B, 0x46, 0x18, 0x17, 0x5D, 0xDF, 0x0D, 0xC6,
0x36, 0x8F, 0xA2, 0xCA, 0x7C, 0xBA, 0x2A, 0x73, 0xD7, 0x15,
0xBF, 0xE2, 0xB3, 0xB7, 0x8E, 0x6E, 0x90, 0x4D, 0x0B, 0x91,
0x70, 0x79, 0x62, 0xBE, 0xF6, 0x0E, 0xC2, 0x69, 0xC1, 0x83,
0x1F, 0xF7, 0x7A, 0xEB, 0x3D, 0xDB, 0x4A, 0x27, 0x7E, 0xE9,
0x58, 0x39, 0xD0, 0xCC, 0x3E, 0x4F
};
unsigned __int64 __fastcall enc(_DWORD* a1, unsigned __int8* src, _BYTE* a3)
{
__m128i v4; // xmm0
__int64 i; // r9
unsigned int v6; // ecx
unsigned int v7; // ebx
int v8; // esi
int v9; // eax
int v10; // ecx
int v11; // esi
unsigned __int64 v12; // rt0
unsigned int v13; // esi
int v14; // eax
int v15; // eax
int v16; // eax
int v17; // eax
_DWORD v19[32]; // [rsp+10h] [rbp-98h] BYREF
memset(v19, 0, sizeof(v19));
v4 = _mm_or_si128(
_mm_or_si128(
_mm_cvtepu8_epi32(
_mm_insert_epi8(
_mm_insert_epi8(_mm_insert_epi8(_mm_cvtsi32_si128(src[15]), src[11], 1), src[7], 2),
src[3],
3)),
_mm_slli_epi32(
_mm_cvtepu8_epi32(
_mm_insert_epi8(
_mm_insert_epi8(_mm_insert_epi8(_mm_cvtsi32_si128(src[14]), src[10], 1), src[6], 2),
src[2],
3)),
8u)),
_mm_or_si128(
_mm_slli_epi32(
_mm_cvtepu8_epi32(
_mm_insert_epi8(
_mm_insert_epi8(_mm_insert_epi8(_mm_cvtsi32_si128(src[13]), src[9], 1), src[5], 2),
src[1],
3)),
0x10u),
_mm_slli_epi32(
_mm_cvtepu8_epi32(
_mm_insert_epi8(
_mm_insert_epi8(_mm_insert_epi8(_mm_cvtsi32_si128(src[12]), src[8], 1), src[4], 2),
*src,
3)),
0x18u)));
for (i = 0LL; i != 32; ++i)
{
int a = _mm_extract_epi32(v4, 1);
v6 = a1[i] ^ a ^ _mm_extract_epi32(v4, 2) ^ _mm_cvtsi128_si32(v4);
int hv6 = HIBYTE(v6);
int b2v6 = BYTE2(v6);
int b1v6 = BYTE1(v6);
v7 = byte_D60[hv6] ^ 7;
v8 = (v7 << 24) | ((byte_D60[b2v6] ^ 7) << 16);
v9 = v8 | ((byte_D60[b1v6] ^ 7) << 8);
v10 = byte_D60[(unsigned __int8)v6] ^ 7;
LODWORD(v12) = v8;
HIDWORD(v12) = v9 + v10;
v11 = v12 >> 22;
HIDWORD(v12) = v9 + v10;
LODWORD(v12) = v9;
int bbb = (v12 >> 14);
int ccc = (__PAIR64__(v10, v9) >> 8);
int eee = ((v7 >> 6) + 4 * (v9 + v10));
int xj = _mm_extract_epi32(v4, 3);
v13 = bbb ^ ccc ^ (v9 + v10) ^ eee ^ v11;
v13 ^= xj;
v19[i] = v13;
v4 = _mm_blend_epi16(_mm_shuffle_epi32(v4, 0x90), _mm_cvtsi32_si128(v13), 3);
}
v14 = v19[31];
*a3 = HIBYTE(v19[31]);
a3[1] = BYTE2(v14);
a3[2] = BYTE1(v14);
a3[3] = v14;
v15 = v19[30];
a3[4] = HIBYTE(v19[30]);
a3[5] = BYTE2(v15);
a3[6] = BYTE1(v15);
a3[7] = v15;
v16 = v19[29];
a3[8] = HIBYTE(v19[29]);
a3[9] = BYTE2(v16);
a3[10] = BYTE1(v16);
a3[11] = v16;
v17 = v19[28];
a3[12] = HIBYTE(v19[28]);
a3[13] = BYTE2(v17);
a3[14] = BYTE1(v17);
a3[15] = v17;
return 0;
}
unsigned int unk_CE0[32] = {
0x00070E12, 0x1C232A36, 0x383F464A, 0x545B626E, 0x70777E82, 0x8C939AA6, 0xA8AFB6BA, 0xC4CBD2DE,
0xE0E7EEF2, 0xFC030A16, 0x181F262A, 0x343B424E, 0x50575E62, 0x6C737A86, 0x888F969A, 0xA4ABB2BE,
0xC0C7CED2, 0xDCE3EAF6, 0xF8FF060A, 0x141B222E, 0x30373E42, 0x4C535A66, 0x686F767A, 0x848B929E,
0xA0A7AEB2, 0xBCC3CAD6, 0xD8DFE6EA, 0xF4FB020E, 0x10171E22, 0x2C333A46, 0x484F565A, 0x646B727E
};
__int64 __fastcall sub_940(_DWORD* a1)
{
unsigned __int32 v1; // r11d
unsigned __int32 v2; // r14d
int v3; // r15d
unsigned int v4; // ecx
__int64 i; // rdx
unsigned __int32 v6; // r10d
unsigned int v7; // ebx
__int64 v8; // rbp
__int64 v9; // rsi
__int64 result; // rax
int v11; // ebx
int v12; // ebx
unsigned __int64 v13; // rt0
*a1 = 1;
v1 = _byteswap_ulong(842084673) ^ 0xA3B1BAC6;
v2 = _byteswap_ulong(926233394) ^ 0x56AA3350;
v3 = 0x534BA9AE;
v4 = 0x8B401286;
for (i = 0LL; i != 32; ++i)
{
v6 = v2;
v2 = v3;
v3 = v4;
v7 = unk_CE0[i] ^ v6 ^ v2 ^ v4 ^ 7;
v8 = BYTE1(v7);
v9 = (unsigned __int8)v7;
result = (unsigned __int8)(byte_D60[HIBYTE(v7)] ^ 7) << 24;
v11 = result | ((byte_D60[BYTE2(v7)] ^ 7) << 16);
LODWORD(v8) = v11 | ((byte_D60[v8] ^ 7) << 8);
LODWORD(v13) = v11;
HIDWORD(v13) = v8 | byte_D60[v9] ^ 7;
v12 = v13 >> 19;
LODWORD(v13) = v8;
v4 = (v13 >> 9) ^ v12 ^ v1 ^ HIDWORD(v13);
a1[i + 1] = v4;
v1 = v6;
}
return result;
}
int main() {
_DWORD v11[34];
_BYTE dest[34];
unsigned char src[50];
memcpy_s(src, 50, (const char*)"wdflag{12312312312312111111111111113112}", 41);
sub_940(v11);
enc(v11, src, dest);
enc(v11, src+16, dest + 16);
enc(v11, src + 32, dest + 16 + 16);
return 0;
}
from regadgets import *
table_a1 = byte2dword(bytes.fromhex("""
01 00 00 00 7f b9 a3 80 d6 ec d4 b9 aa ec 25 74
65 d3 9b 33 13 8b d1 a5 de a4 a7 56 3e c7 07 e9
a9 04 aa d0 28 7f 82 6c 6a 19 97 e9 d8 2a 2f 0c
a5 6d 9d fd 6d da 4d 16 a4 c2 dc 5f b7 87 99 48
78 59 ef fd ca 1a c2 96 59 62 f4 7f 4e c9 ad b9
6d 56 fb 47 43 c9 cf 8c 36 e3 a5 8d 1b d4 49 1b
75 a1 47 66 68 90 de c3 94 87 70 f6 91 b1 4a e9
a4 89 0b 54 20 a3 ab b6 d0 64 77 2a a7 90 c4 ed
"""))
byte_d60 = [ 0xD1, 0x97, 0xEE, 0xF9, 0xCB, 0xE6, 0x3A, 0xB0, 0x11, 0xB1,
0x13, 0xC5, 0x2F, 0xFC, 0x2B, 0x02, 0x2C, 0x60, 0x9D, 0x71,
0x2D, 0xB9, 0x03, 0xC4, 0xAD, 0x43, 0x14, 0x21, 0x4E, 0x81,
0x01, 0x9E, 0x9B, 0x45, 0x57, 0xF3, 0x96, 0xE8, 0x9F, 0x7D,
0x34, 0x53, 0x0C, 0x44, 0xEA, 0xC8, 0xAB, 0x65, 0xE3, 0xB4,
0x1B, 0xAE, 0xCE, 0x0F, 0xEF, 0x92, 0x87, 0xD8, 0x93, 0xFD,
0x72, 0x88, 0x38, 0xA1, 0x40, 0x00, 0xA0, 0xFB, 0xF4, 0x74,
0x10, 0xBD, 0x84, 0x5E, 0x3B, 0x1E, 0xE1, 0x82, 0x48, 0xAF,
0x6F, 0x6C, 0x86, 0xB5, 0x76, 0x63, 0xDD, 0x8C, 0xFF, 0xEC,
0x08, 0x4C, 0x77, 0x51, 0x9A, 0x32, 0x19, 0x23, 0x09, 0x59,
0x64, 0x5F, 0xD6, 0xA5, 0x22, 0x25, 0x7B, 0x3C, 0x06, 0x26,
0x7F, 0x80, 0xD3, 0x07, 0x41, 0x50, 0x98, 0xD4, 0x20, 0x55,
0x4B, 0x31, 0x05, 0xE0, 0xA7, 0xC3, 0xCF, 0x99, 0xED, 0xB8,
0x8D, 0xD5, 0x47, 0xC0, 0x3F, 0xB2, 0xA4, 0xF0, 0xF5, 0xC9,
0xFE, 0x66, 0x12, 0xA6, 0xE7, 0xA9, 0x5A, 0xA3, 0x9C, 0x33,
0x1D, 0x52, 0xAA, 0x94, 0x35, 0x37, 0xF2, 0x8B, 0xB6, 0xE4,
0x1A, 0xF1, 0xE5, 0x29, 0x85, 0x61, 0xCD, 0x67, 0xC7, 0x2E,
0x24, 0xAC, 0x0A, 0x54, 0x49, 0x68, 0xD2, 0xDC, 0x30, 0x42,
0xD9, 0xFA, 0x89, 0x28, 0x04, 0xF8, 0x6D, 0x75, 0x6A, 0x6B,
0x5C, 0x56, 0x8A, 0x1C, 0xA8, 0x95, 0xBC, 0xDA, 0xBB, 0x78,
0x16, 0xDE, 0x5B, 0x46, 0x18, 0x17, 0x5D, 0xDF, 0x0D, 0xC6,
0x36, 0x8F, 0xA2, 0xCA, 0x7C, 0xBA, 0x2A, 0x73, 0xD7, 0x15,
0xBF, 0xE2, 0xB3, 0xB7, 0x8E, 0x6E, 0x90, 0x4D, 0x0B, 0x91,
0x70, 0x79, 0x62, 0xBE, 0xF6, 0x0E, 0xC2, 0x69, 0xC1, 0x83,
0x1F, 0xF7, 0x7A, 0xEB, 0x3D, 0xDB, 0x4A, 0x27, 0x7E, 0xE9,
0x58, 0x39, 0xD0, 0xCC, 0x3E, 0x4F]
def encrypt(x):
for i in range(32):
v1 = table_a1[i] ^ x[0] ^ x[1] ^ x[2]
a = byte_d60[(v1 >> 24) & 0xff] ^ 7
b = byte_d60[(v1 >> 16) & 0xff] ^ 7
c = byte_d60[(v1 >> 8) & 0xff] ^ 7
d = byte_d60[(v1 >> 0) & 0xff] ^ 7
v = a << 24 | b << 16 | c << 8 | d
mask = ror32(v, 30) ^ ror32(v, 22) ^ ror32(v, 14) ^ ror32(v, 8) ^ v
x[0], x[1], x[2], x[3] = mask ^ x[3], x[0], x[1], x[2]
return x
def decrypt(x):
for i in range(32):
v1 = table_a1[31 - i] ^ x[1] ^ x[2] ^ x[3]
a = byte_d60[(v1 >> 24) & 0xff] ^ 7
b = byte_d60[(v1 >> 16) & 0xff] ^ 7
c = byte_d60[(v1 >> 8) & 0xff] ^ 7
d = byte_d60[(v1 >> 0) & 0xff] ^ 7
v = a << 24 | b << 16 | c << 8 | d
mask = ror32(v, 30) ^ ror32(v, 22) ^ ror32(v, 14) ^ ror32(v, 8) ^ v
x3 = x[0] ^ mask
x[0], x[1], x[2], x[3] = x[1], x[2], x[3], x3
return x
enc =[0x4D, 0xA0, 0xFC, 0xEA, 0x2F, 0x84, 0x1D, 0x8F, 0xA1, 0x98, 0xA8, 0xC8, 0xC7, 0x29, 0xD8, 0xD9, 0xA0, 0xE4, 0x72, 0xEC, 0xD7, 0x48, 0x7F, 0x5A, 0xA9, 0x0D, 0x34, 0x35, 0xCB, 0x22, 0xC9, 0x11, 0xA3, 0x6E, 0xC9, 0x27, 0xDA, 0x4D, 0x64, 0x24, 0x34, 0x6B, 0xB4, 0xED, 0x28, 0x21, 0x51, 0xF3]
print(bytes(enc).hex())
enc = byte2dword([0x4D, 0xA0, 0xFC, 0xEA, 0x2F, 0x84, 0x1D, 0x8F, 0xA1, 0x98, 0xA8, 0xC8, 0xC7, 0x29, 0xD8, 0xD9, 0xA0, 0xE4, 0x72, 0xEC, 0xD7, 0x48, 0x7F, 0x5A, 0xA9, 0x0D, 0x34, 0x35, 0xCB, 0x22, 0xC9, 0x11, 0xA3, 0x6E, 0xC9, 0x27, 0xDA, 0x4D, 0x64, 0x24, 0x34, 0x6B, 0xB4, 0xED, 0x28, 0x21, 0x51, 0xF3])
enc = dword2byte(enc)
r = []
for i in range(0, len(enc), 4):
r.append(b2l(bytes(enc[i:i+4])))
enc = r
result = b''
if __name__ == '__main__':
for i in range(0, len(enc), 4):
vv = enc[i:i+4]
print(vv)
result += dword2byte(decrypt(vv))[::-1]
print(result)
当时抄出来这个的时候没反应过来是SM4,最后在老学长指点下才明白。
直接把key弄出来,然后enc放CyberChef就秒了...
REVERSE02
过于简单的签到题,四个不一样的加密/编码,直接CyberChef就秒了。