NCTF2024
ezDOS
MS-DOS on Intel 8086,先去一下花指令,ida打开分析过汇编,但是感觉提不出什么有用的信息,并且密文看着也很奇怪
那就只能用DOSBox来动态调试了,断点下在0020处,就是输出提示Show me your flag:,然后输入假flag,
NCTF{AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA},查看内存,使用指令d 0168,
可以看到这里存储输入明文的地方
然后继续往下跟,发现一直到loc_10582,才对输入的flag进行了加密
异或处理
然后加密完之后查看内存
发现前几位和最后一位的数据是和这里是一样的
并且位数也对的上,38位
那么就可以根据假flag和其加密结果反推出异或的key,就可以和密文进行异或解密了
key
解密
拿到flag
NCTF{Y0u_4r3_Assemb1y_M4st3r_5d0b497e}
SafeProgram
魔改SM4,改了两个常量。TLS1里有反调试,直接nop掉就可以了,然后动调取sbox和FK,动调的时候记得把Sleep也nop掉了,不然还得等,然后就可以直接写脚本解密了
#include <string.h>
#include <stdio.h>
#include <time.h>
/*--------------------------------------------------------------------------------------------------------------*/
#define SM4_ENCRYPT 1
#define SM4_DECRYPT 0
/*--------------------------------------------------------------------------------------------------------------*/
/**
* \brief SM4 context structure
*/
typedef struct
{
int mode; /*!< encrypt/decrypt */
unsigned long sk[32]; /*!< SM4 subkeys */
} sm4_context;
/*--------------------------------------------------------------------------------------------------------------*/
/**
* \brief SM4 key schedule (128-bit, encryption)
*
* \param ctx SM4 context to be initialized
* \param key 16-byte secret key
*/
void sm4_setkey_enc(sm4_context *ctx, unsigned char key[16]);
/*--------------------------------------------------------------------------------------------------------------*/
/**
* \brief SM4 key schedule (128-bit, decryption)
*
* \param ctx SM4 context to be initialized
* \param key 16-byte secret key
*/
void sm4_setkey_dec(sm4_context *ctx, unsigned char key[16]);
/*--------------------------------------------------------------------------------------------------------------*/
/**
* \brief SM4-ECB block encryption/decryption
* \param ctx SM4 context
* \param mode SM4_ENCRYPT or SM4_DECRYPT
* \param length length of the input data
* \param input input block
* \param output output block
*/
void sm4_crypt_ecb(sm4_context *ctx,
int mode,
int length,
unsigned char *input,
unsigned char *output);
/*--------------------------------------------------------------------------------------------------------------*/
/**
* \brief SM4-CBC buffer encryption/decryption
* \param ctx SM4 context
* \param mode SM4_ENCRYPT or SM4_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*/
void sm4_crypt_cbc(sm4_context *ctx,
int mode,
int length,
unsigned char iv[16],
unsigned char *input,
unsigned char *output);
/*--------------------------------------------------------------------------------------------------------------*/
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_ULONG_BE
#define GET_ULONG_BE(n, b, i) \
{ \
(n) = ((unsigned long)(b)[(i)] << 24) | ((unsigned long)(b)[(i) + 1] << 16) | ((unsigned long)(b)[(i) + 2] << 8) | ((unsigned long)(b)[(i) + 3]); \
}
#endif
/*--------------------------------------------------------------------------------------------------------------*/
#ifndef PUT_ULONG_BE
#define PUT_ULONG_BE(n, b, i) \
{ \
(b)[(i)] = (unsigned char)((n) >> 24); \
(b)[(i) + 1] = (unsigned char)((n) >> 16); \
(b)[(i) + 2] = (unsigned char)((n) >> 8); \
(b)[(i) + 3] = (unsigned char)((n)); \
}
#endif
/*--------------------------------------------------------------------------------------------------------------*/
/*
*rotate shift left marco definition
*
*/
#define SHL(x, n) (((x) & 0xFFFFFFFF) << n)
#define ROTL(x, n) (SHL((x), n) | ((x) >> (32 - n)))
#define SWAP(a, b) \
{ \
unsigned long t = a; \
a = b; \
b = t; \
t = 0; \
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* Expanded SM4 S-boxes
/* Sbox table: 8bits input convert to 8 bits output*/ //已被魔改
static const unsigned char SboxTable[16][16] =
{
{0xD1, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 0x05},
{0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99},
{0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62},
{0xE4, 0xB3, 0x17, 0xA9, 0x1C, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 0xA6},
{0x47, 0x07, 0xA7, 0x4F, 0xF3, 0x73, 0x71, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0xD6, 0xA8},
{0x68, 0x6B, 0x81, 0xB2, 0xFC, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35},
{0x1E, 0x24, 0x0E, 0x78, 0x63, 0x58, 0x9F, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0xC9, 0x87},
{0xD4, 0x00, 0x46, 0x57, 0x5E, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E},
{0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1},
{0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 0xE3},
{0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F},
{0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51},
{0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 0xD8},
{0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0},
{0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84},
{0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 0x48}};
/*--------------------------------------------------------------------------------------------------------------*/
/* System parameter */
static const unsigned long FK[4] =
{0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc}; //已被魔改
/*--------------------------------------------------------------------------------------------------------------*/
/* fixed parameter */
static const unsigned long CK[32] =
{
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279};
/*--------------------------------------------------------------------------------------------------------------*/
/*
* private function:
* look up in SboxTable and get the related value.
* args: [in] inch: 0x00~0xFF (8 bits unsigned value).
*/
static unsigned char sm4Sbox(unsigned char inch)
{
unsigned char *pTable = (unsigned char *)SboxTable;
unsigned char retVal = (unsigned char)(pTable[inch]);
return retVal;
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* private F(Lt) function:
* "T algorithm" == "L algorithm" + "t algorithm".
* args: [in] a: a is a 32 bits unsigned value;
* return: c: c is calculated with line algorithm "L" and nonline algorithm "t"
*/
static unsigned long sm4Lt(unsigned long ka)
{
unsigned long bb = 0;
unsigned long c = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka, a, 0)
b[0] = sm4Sbox(a[0]);
b[1] = sm4Sbox(a[1]);
b[2] = sm4Sbox(a[2]);
b[3] = sm4Sbox(a[3]);
GET_ULONG_BE(bb, b, 0)
c = bb ^ (ROTL(bb, 2)) ^ (ROTL(bb, 10)) ^ (ROTL(bb, 18)) ^ (ROTL(bb, 24));
return c;
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* private F function:
* Calculating and getting encryption/decryption contents.
* args: [in] x0: original contents;
* args: [in] x1: original contents;
* args: [in] x2: original contents;
* args: [in] x3: original contents;
* args: [in] rk: encryption/decryption key;
* return the contents of encryption/decryption contents.
*/
static unsigned long sm4F(unsigned long x0, unsigned long x1, unsigned long x2, unsigned long x3, unsigned long rk)
{
return (x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk));
}
/*--------------------------------------------------------------------------------------------------------------*/
/* private function:
* Calculating round encryption key.
* args: [in] a: a is a 32 bits unsigned value;
* return: sk[i]: i{0,1,2,3,...31}.
*/
static unsigned long sm4CalciRK(unsigned long ka)
{
unsigned long bb = 0;
unsigned long rk = 0;
unsigned char a[4];
unsigned char b[4];
PUT_ULONG_BE(ka, a, 0)
b[0] = sm4Sbox(a[0]);
b[1] = sm4Sbox(a[1]);
b[2] = sm4Sbox(a[2]);
b[3] = sm4Sbox(a[3]);
GET_ULONG_BE(bb, b, 0)
rk = bb ^ (ROTL(bb, 13)) ^ (ROTL(bb, 23));
return rk;
}
/*--------------------------------------------------------------------------------------------------------------*/
static void sm4_setkey(unsigned long SK[32], unsigned char key[16])
{
unsigned long MK[4];
unsigned long k[36];
unsigned long i = 0;
GET_ULONG_BE(MK[0], key, 0);
GET_ULONG_BE(MK[1], key, 4);
GET_ULONG_BE(MK[2], key, 8);
GET_ULONG_BE(MK[3], key, 12);
k[0] = MK[0] ^ FK[0];
k[1] = MK[1] ^ FK[1];
k[2] = MK[2] ^ FK[2];
k[3] = MK[3] ^ FK[3];
for (; i < 32; i++)
{
k[i + 4] = k[i] ^ (sm4CalciRK(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i]));
SK[i] = k[i + 4];
}
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* SM4 standard one round processing
*
*/
static void sm4_one_round(unsigned long sk[32],
unsigned char input[16],
unsigned char output[16])
{
unsigned long i = 0;
unsigned long ulbuf[36];
memset(ulbuf, 0, sizeof(ulbuf));
GET_ULONG_BE(ulbuf[0], input, 0)
GET_ULONG_BE(ulbuf[1], input, 4)
GET_ULONG_BE(ulbuf[2], input, 8)
GET_ULONG_BE(ulbuf[3], input, 12)
while (i < 32)
{
ulbuf[i + 4] = sm4F(ulbuf[i], ulbuf[i + 1], ulbuf[i + 2], ulbuf[i + 3], sk[i]);
i++;
}
PUT_ULONG_BE(ulbuf[35], output, 0);
PUT_ULONG_BE(ulbuf[34], output, 4);
PUT_ULONG_BE(ulbuf[33], output, 8);
PUT_ULONG_BE(ulbuf[32], output, 12);
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* SM4 key schedule (128-bit, encryption)
*/
void sm4_setkey_enc(sm4_context *ctx, unsigned char key[16])
{
ctx->mode = SM4_ENCRYPT;
sm4_setkey(ctx->sk, key);
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* SM4 key schedule (128-bit, decryption)
*/
void sm4_setkey_dec(sm4_context *ctx, unsigned char key[16])
{
int i;
ctx->mode = SM4_ENCRYPT;
sm4_setkey(ctx->sk, key);
for (i = 0; i < 16; i++)
{
SWAP(ctx->sk[i], ctx->sk[31 - i]);
}
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* SM4-ECB block encryption/decryption
*/
void sm4_crypt_ecb(sm4_context *ctx,
int mode,
int length,
unsigned char *input,
unsigned char *output)
{
while (length > 0)
{
sm4_one_round(ctx->sk, input, output);
input += 16;
output += 16;
length -= 16;
}
}
/*--------------------------------------------------------------------------------------------------------------*/
/*
* SM4-CBC buffer encryption/decryption
*/
void sm4_crypt_cbc(sm4_context *ctx,
int mode,
int length,
unsigned char iv[16],
unsigned char *input,
unsigned char *output)
{
int i;
unsigned char temp[16];
if (mode == SM4_ENCRYPT)
{
while (length > 0)
{
for (i = 0; i < 16; i++)
output[i] = (unsigned char)(input[i] ^ iv[i]);
sm4_one_round(ctx->sk, output, output);
memcpy(iv, output, 16);
input += 16;
output += 16;
length -= 16;
}
}
else /* SM4_DECRYPT */
{
while (length > 0)
{
memcpy(temp, input, 16);
sm4_one_round(ctx->sk, input, output);
for (i = 0; i < 16; i++)
output[i] = (unsigned char)(output[i] ^ iv[i]);
memcpy(iv, temp, 16);
input += 16;
output += 16;
length -= 16;
}
}
}
/*--------------------------------------------------------------------------------------------------------------*/
int main()
{
unsigned char key[16] = {0x4E, 0x43, 0x54, 0x46, 0x32, 0x34, 0x6E, 0x63, 0x74, 0x66,
0x4E, 0x43, 0x54, 0x46, 0x32, 0x34};
unsigned char input[32] = {
0xFB, 0x97, 0x3C, 0x3B, 0xF1, 0x99, 0x12, 0xDF,
0x13, 0x30, 0xF7, 0xD8, 0x7F, 0xEB, 0xA0, 0x6C,
0x14, 0x5B, 0xA6, 0x2A, 0xA8, 0x05, 0xA5, 0xF3,
0x76, 0xBE, 0xC9, 0x01, 0xF9, 0x36, 0x7B, 0x46
};
unsigned char output[16];
sm4_context ctx;
unsigned long i;
/*
//encrypt testing
sm4_setkey_enc(&ctx,key);
sm4_crypt_ecb(&ctx,1,16,input,output);
for(i=0;i<16;i++)
printf("%02x ", output[i]);
printf("\n");
*/
// decrypt testing
sm4_setkey_dec(&ctx, key);
sm4_crypt_ecb(&ctx, 0, 32, input, output);
for (i = 0; i < 32; i++)
printf("%c", output[i]);
printf("\n");
return 0;
}
NCTF{58cb925e0cd823c0d0b54fd06b820b7e}
x1Login
安卓逆向,有动调和root检测,frida写个脚本hook就能过掉。程序整体逻辑就是,native层的libsimple.so文件负责对调用的dex文件名进行加密,魔改的base64编码和异或,然后另外一个so文件就是负责密码的加密。
root检测等
调用check方法
在assets文件夹里找到libsimple.so文件,把前面elf的文件头去掉,改下后缀成dex,就可以用jadx反编译了
package com.nctf.simplelogin;
import android.content.Context;
import android.widget.Toast;
import java.security.MessageDigest;
/* loaded from: C:\Users\16219\Desktop\x1Login-release\assets\libsimple.dex */
public class Check {
Context context;
String password;
String username;
public Check(Context context, String username, String password) {
this.username = username;
this.password = password;
this.context = context;
}
public void check() {
try {
if (check_username()) {
MessageDigest digest = MessageDigest.getInstance(DecStr.get("tMC2"));
digest.update(this.username.getBytes());
byte[] output = digest.digest();
boolean result = check_password(output);
if (result) {
Toast.makeText(this.context, "Login Successful! Now submit your flag!", 0).show();
return;
}
}
Toast.makeText(this.context, "Login Failed!", 0).show();
} catch (Exception e) {
e.printStackTrace();
}
}
private boolean check_username() {
return this.username.equals(DecStr.get("uZPOs29goMu6l38="));
}
private boolean check_password(byte[] key) {
return Secure.doCheck(this.password, key);
}
}
解密拿到用户名
这题的check机制有问题,输入正确的用户名,不输入密码,然后登录会显示成功。接着在libnative.so文件里分析密码是如果check的,首先是将用户名的md5传进去做key,再加密
但是分析无果,不知道是啥算法
在sub_1E30函数里看到有日志打印,但是拿不到输出的内容
赛后p34cd0wn师傅复现出来了,这确实是3DES加密,并且是标准的,我觉得应该是被优化的太厉害了,常量,密文,key的端序都发生了改变
这是密文,密钥就是用户名md5
解密
NCTF{X1c@dM1n1$t_SafePWD~5y$x?YM+5U05Gm6=}
gogo
第一次完整的复现一道vm,并且还学到了新方法,以前只会傻乎乎的找opcode,然后输出所有操作指令,再去进行分析,但这种硬撕,如果水平较低的话只能解决一些简单的vm,如果复杂的话那就很吃操作了。
go语言写的,但是整体代码逻辑还是较为清晰,但也还是要借助ai来辅助分析,不是很会go语言
// main.main
void __fastcall main_main()
{
int v0; // ecx
int v1; // edi
int v2; // esi
int v3; // r8d
int v4; // r9d
__int64 v5; // r14
int v6; // ecx
int v7; // r8d
int v8; // r9d
int v9; // ecx
int v10; // r8d
int v11; // r9d
int v12; // r8d
int v13; // r9d
int v14; // r10d
int v15; // r11d
int v16; // r10d
int v17; // r11d
main_coroutVM *p_main_coroutVM; // rax
char *v19; // rdx
void *v20; // rcx
void *v21; // rbx
_QWORD *v22; // r11
void *v23; // rsi
_QWORD *v24; // r11
main_coroutVM *v25; // rax
__int64 v26; // rcx
_QWORD *v27; // r11
void *v28; // r8
void *v29; // r9
void *v30; // r10
size_t v31; // rdx
main_coroutVM *v32; // rsi
uint8 *mem; // rdi
__int64 v34; // rbx
main_coroutVM *v35; // rbx
_QWORD *v36; // rax
int v37; // r8d
int v38; // r9d
int v39; // r10d
main_coroutVM **v40; // r11
main_coroutVM *v41; // rcx
_QWORD *v42; // rax
int v43; // r8d
int v44; // r9d
int v45; // r10d
main_coroutVM **v46; // r11
main_coroutVM *v47; // rcx
__int64 v48; // rcx
unsigned __int64 i; // rax
int v50; // r8d
int v51; // r9d
int v52; // r10d
int v53; // r11d
char v54; // cl
__int64 v55; // r8
__int64 v56; // [rsp-3Ah] [rbp-E0h]
__int64 v57; // [rsp-3Ah] [rbp-E0h]
__int64 v58; // [rsp-3Ah] [rbp-E0h]
__int64 v59; // [rsp-3Ah] [rbp-E0h]
__int64 v60; // [rsp-3Ah] [rbp-E0h]
__int64 v61; // [rsp-32h] [rbp-D8h]
__int64 v62; // [rsp-32h] [rbp-D8h]
__int64 v63; // [rsp-32h] [rbp-D8h]
__int64 v64; // [rsp-2Ah] [rbp-D0h]
__int64 v65; // [rsp-22h] [rbp-C8h]
__int64 v66; // [rsp-1Ah] [rbp-C0h]
char v67; // [rsp+0h] [rbp-A6h]
int v68; // [rsp+1h] [rbp-A5h] BYREF
char v69; // [rsp+5h] [rbp-A1h] BYREF
size_t len; // [rsp+6h] [rbp-A0h]
unsigned __int64 v71; // [rsp+Eh] [rbp-98h]
void *v72; // [rsp+16h] [rbp-90h]
main_coroutVM *v73; // [rsp+1Eh] [rbp-88h]
void *v74; // [rsp+26h] [rbp-80h]
main_coroutVM *v75; // [rsp+2Eh] [rbp-78h]
void *v76; // [rsp+36h] [rbp-70h]
main_coroutVM *v77; // [rsp+3Eh] [rbp-68h]
char *ptr; // [rsp+46h] [rbp-60h] BYREF
__int64 v79[2]; // [rsp+4Eh] [rbp-58h] BYREF
__int64 v80[2]; // [rsp+5Eh] [rbp-48h] BYREF
__int64 v81[2]; // [rsp+6Eh] [rbp-38h] BYREF
__int64 v82[2]; // [rsp+7Eh] [rbp-28h] BYREF
__int64 v83[2]; // [rsp+8Eh] [rbp-18h] BYREF
string *p_string; // [rsp+9Eh] [rbp-8h]
while ( &ptr <= *(v5 + 16) )
runtime_morestack_noctxt();
v74 = runtime_makechan(&RTYPE_chan__4_uint8, 0, v0, v1, v2, v3, v4);// 初始化三个通道
v72 = runtime_makechan(&RTYPE_chan__4_uint8, 0, v6, v1, v2, v7, v8);
v76 = runtime_makechan(&RTYPE_chan_bool, 2, v9, v1, v2, v10, v11);
p_string = runtime_newobject(&RTYPE_string);
v83[0] = &RTYPE_string;
v83[1] = &off_478B08;
fmt_Fprintln(off_479218, qword_510000, v83, 1, 1, v12, v13, v14, v15, v56, v61);// 交互提示输出
v82[0] = &RTYPE__ptr_string;
v82[1] = p_string;
fmt_Fscanf(
off_479238,
qword_50FFF8,
"%si), )(tvrRuUeEaAlLsS01bBoOxX+-nNiIfFpPLlLtLuMn: 25\"\n [(\"\")) )\n @s -> Pn=][}\n]\n> \n \t +osnil01_EOFintmapptr",
2,
v82,
1,
1,
v16,
v17,
v57,
v62,
v64,
HIDWORD(v64),
v65,
HIDWORD(v65),
v66,
HIDWORD(v66));
ptr = p_string->ptr;
len = p_string->len;
p_main_coroutVM = runtime_newobject(&RTYPE_main_coroutVM);
v19 = &unk_555420;
if ( ptr )
v19 = ptr;
if ( dword_555690 )
{
p_main_coroutVM = runtime_gcWriteBarrier2(p_main_coroutVM);
v20 = v74;
*v22 = v74;
v21 = v76;
v22[1] = v76;
}
else
{
v20 = v74;
v21 = v76;
}
v77 = v19;
p_main_coroutVM->instr = v20;
p_main_coroutVM->checkres = v21;
v23 = qword_50FFC0;
if ( dword_555690 )
{
p_main_coroutVM = runtime_gcWriteBarrier1(p_main_coroutVM, v21, v20, 2LL, qword_50FFC0);
*v24 = v23;
}
v75 = p_main_coroutVM;
p_main_coroutVM->instrSet = v23;
v25 = runtime_newobject(&RTYPE_main_coroutVM);
if ( dword_555690 )
{
v25 = runtime_gcWriteBarrier2(v25);
v28 = v72;
*v27 = v72;
v29 = v76;
v27[1] = v76;
}
else
{
v28 = v72;
v29 = v76;
}
v25->instr = v28;
v25->checkres = v29;
v30 = qword_50FFC8;
if ( dword_555690 )
{
v25 = runtime_gcWriteBarrier1(v25, v21, v26, 2LL, v23);
*v27 = v30;
}
v25->instrSet = v30;
if ( p_string->len == 40 ) // 长度检测,必须是40
{
v31 = len;
if ( len < 20 ) // 字符串分割,分割前20字节
runtime_panicSliceAcap(v25, v21, 20LL);
v73 = v25;
v32 = v75;
mem = v75->mem;
v34 = v77;
if ( v77 != v75->mem )
{
runtime_memmove(v75->mem, v77, 20LL);
v25 = v73;
v31 = len;
v34 = v77;
v32 = v75;
}
if ( v31 < 0x28 ) // 字符串分割,分割后20字节
runtime_panicSliceAcap(v25, v34, 40LL);
v35 = (v34 + 20);
if ( v35 != v25->mem )
runtime_memmove(v25->mem, v35, 20LL);
v36 = runtime_newobject(&unk_43CF60); // 创建第一个协程
*v36 = main_main_gowrap1; // 第一个协程入口
if ( dword_555690 )
{
v36 = runtime_gcWriteBarrier1(v36, v35, main_main_gowrap1, mem, v32);
v41 = v75;
*v40 = v75;
}
else
{
v41 = v75;
}
v36[1] = v41; // 传参
runtime_newproc(v36, v35, v41, mem, v32, v37, v38, v39, v40, v58);// 启动协程
v42 = runtime_newobject(&unk_43CF60); // 创建第二个协程
*v42 = main_main_gowrap2; // 第二个协程入口
if ( dword_555690 )
{
v42 = runtime_gcWriteBarrier1(v42, v35, main_main_gowrap2, mem, v32);
v47 = v73;
*v46 = v73;
}
else
{
v47 = v73;
}
v42[1] = v47; // 传递参数
runtime_newproc(v42, v35, v47, mem, v32, v43, v44, v45, v46, v59);// 协程启动
v48 = v74;
for ( i = 0LL; qword_508478 > i; i = v71 ) // 数据发送
{
v68 = 0;
if ( qword_508480 < i + 4 ) // 中间这部分是边界检查
runtime_panicSliceAcap(i, v35, i + 4);
if ( i > i + 4 )
runtime_panicSliceB(i, v35, i + 4);
v71 = i + 4;
v55 = ((i - qword_508480) >> 63) & i;
if ( &v68 != (off_508470 + v55) )
v68 = *(off_508470 + v55);
runtime_chansend1(v48); // 发送到第一个通道
v35 = &v68;
runtime_chansend1(v72); // 发送到第二个通道
v48 = v74;
}
}
else
{
v81[0] = &RTYPE_string;
v81[1] = &off_478B18;
fmt_Fprintln(off_479218, qword_510000, v81, 1, 1, v28, v29, p_string, v27, v58, v63);
}
v69 = 0;
runtime_chanrecv1(v76, &v69); // 接受第一个结果
v67 = v69;
v69 = 0;
runtime_chanrecv1(v76, &v69); // 接受第二个结果
v54 = v69;
v69 = v67;
if ( v67 )
v69 = v54;
if ( v69 )
{
v80[0] = &RTYPE_string;
v80[1] = &off_478B28; // correct
fmt_Fprintln(off_479218, qword_510000, v80, 1, 1, v50, v51, v52, v53, v60, v63);
}
else
{
v79[0] = &RTYPE_string; // wrong
v79[1] = &off_478B38;
fmt_Fprintln(off_479218, qword_510000, v79, 1, 1, v50, v51, v52, v53, v60, v63);
}
}
代码具体意思已经注释在代码中了
并且程序把每种运算的函数指令啥的都已经给出来了
这里要注意的是,flag字符串被分成两部分,两部分加密的算法虽然都是xxtea,但是具体有些细节不一样。
那么我们就可以在每个运算函数打下断点,然后当调用该函数的时候,读取响应寄存器的值,将寄存器种的值输出,并且以该运算对应的格式输出。
base = 0x380000
def set_python_bpt(ea, cond):
''' Set conditional breakpoint with Python function
Usage:
set_python_bpt(0x08000688, 'view_regs()')
'''
idaapi.add_bpt(ea, 4, BPT_DEFAULT)
bpt = idaapi.bpt_t()
idaapi.get_bpt(ea, bpt)
bpt.elang = 'Python'
bpt.condition = cond
idaapi.update_bpt(bpt)
def hook_shl():
ebx = idc.get_reg_value("ebx")
cl = idc.get_reg_value("cl")
val1 = ebx
val2 = cl
print(f"{val1:x} << {val2:x} = {(val1 << val2) & 0xFFFFFFFF:x}")
def hook_shr():
ebx = idc.get_reg_value("ebx")
cl = idc.get_reg_value("cl")
val1 = ebx
val2 = cl
print(f"{val1:x} >> {val2:x} = {(val1 >> val2) & 0xFFFFFFFF:x}")
def hook_add():
edx = idc.get_reg_value("edx")
rax = idc.get_reg_value("rax")
rbx = idc.get_reg_value("rbx")
val1 = edx
val2 = idc.get_wide_dword(rax + rbx * 4)
print(f"{val1:x} + {val2:x} = {(val1 + val2) & 0xFFFFFFFF:x}")
def hook_xor():
edx = idc.get_reg_value("edx")
rax = idc.get_reg_value("rax")
rbx = idc.get_reg_value("rbx")
val1 = edx
val2 = idc.get_wide_dword(rax + rbx * 4)
print(f"{val1:x} ^ {val2:x} = {(val1 ^ val2) & 0xFFFFFFFF:x}")
def hook_sub():
edx = idc.get_reg_value("edx")
rax = idc.get_reg_value("rax")
rbx = idc.get_reg_value("rbx")
val1 = edx
val2 = idc.get_wide_dword(rax + rbx * 4)
print(f"{val1:x} - {val2:x} = {(val1 - val2) & 0xFFFFFFFF:x}")
def hook_mul():
edx = idc.get_reg_value("edx")
ebx = idc.get_reg_value("ebx")
val1 = edx
val2 = ebx
print(f"{val1:x} * {val2:x} = {(val1 * val2) & 0xFFFFFFFF:x}")
def hook_and():
edx = idc.get_reg_value("edx")
rax = idc.get_reg_value("rax")
rbx = idc.get_reg_value("rbx")
val1 = edx
val2 = idc.get_wide_dword(rax + rbx * 4)
print(f"{val1:x} & {val2:x} = {(val1 & val2) & 0xFFFFFFFF:x}")
set_python_bpt(base + 0x0000000000A8860, 'hook_shr()')
set_python_bpt(base + 0x0000000000A8820, 'hook_shl()')
set_python_bpt(base + 0x00000000000A871D, 'hook_add()')
set_python_bpt(base + 0x00000000000A87DD, 'hook_xor()')
set_python_bpt(base + 0x00000000000A875D, 'hook_sub()')
set_python_bpt(base + 0x0000000000A87A0, 'hook_mul()')
set_python_bpt(base + 0x0000000000A889A, 'hook_and()')
print('ok')
这里还有一个点是需要注意基地址要为动态调试的时候程序的基地址,不然不会有输出的。
在输出窗口拿到输出,仔细分析下来,是两部分字符串加密时混在一起的,需要分开来
这里展示一部分
9e37 << 10 = 9e370000
79b9 + 9e370000 = 9e3779b9
9e37 << 10 = 9e370000
79b9 + 9e370000 = 9e3779b9
# tmp1 = (v[4] >> 5) ^ (v[1] <<2)
48474645 << 2 = 211d1914
54535251 >> 5 = 2a29a92
211d1914 ^ 2a29a92 = 23bf8386
# tmp3 = (v[1] >> 3) ^ (v[4] << 4)
48474645 >> 3 = 908e8c8
54535251 << 4 = 45352510
908e8c8 ^ 45352510 = 4c3dcdd8
# tmp4 = (v[4] >> 5) ^ (v[1] <<2) + (v[1] >> 3) ^ (v[4] <<4)
23bf8386 + 4c3dcdd8 = 6ffd515e
# e = (sum >> 2) & 3;
9e3779b9 >> 2 = 278dde6e
278dde6e & 3 = 2
# (p & 3) ^ e
2 ^ 0 = 2
# (sum ^ v[1])
9e3779b9 ^ 48474645 = d6703ffc
# (key[(p&3)^e] ^ z)
54535251 ^ a78c0b4f = f3df591e
# (sum^y) + (key[(p&3)^e] ^ z))
d6703ffc + f3df591e = ca4f991a
# MX = ((v[4] >> 5) ^ (v[1] <<2) + (v[1] >> 3) ^ (v[4] << 4)) ^ (sum ^ v[1]) + (key[(p&3)^e] ^ v[4]))
6ffd515e ^ ca4f991a = a5b2c844
# z = v[0] += MX
a5b2c844 + 44434241 = e9f60a85
# tmp2 = (v[6] >> 2) ^ (v[9] <<5)
62615a59 >> 2 = 18985696
6e6d6c6b << 5 = cdad8d60
18985696 ^ cdad8d60 = d535dbf6
# tmp5 = (v[6] << 3) ^ (v[9] >> 4)
62615a59 << 3 = 130ad2c8
6e6d6c6b >> 4 = 6e6d6c6
130ad2c8 ^ 6e6d6c6 = 15ec040e
# tmp6 = tmp2 + tmp5
# tmp6 = (v[6] >> 2) ^ (v[9] << 5) + (v[6] <<3) ^ (v[9] >> 4)
d535dbf6 + 15ec040e = eb21e004
a78c << 10 = a78c0000
b4f + a78c0000 = a78c0b4f
9f1c << 10 = 9f1c0000
# e = (sum >> 2) & 3;
2 & 3 = 2
9e3779b9 >> 2 = 278dde6e
278dde6e & 3 = 2
2 * 4 = 8
2 ^ 0 = 2
8 + 20 = 28
2 & 3 = 2
# get key[0]
f72e + 9f1c0000 = 9f1cf72e
2 * 4 = 8
8 + 20 = 28
# (sum ^ v[6])
9e3779b9 ^ 62615a59 = fc5623e0
# (key[( p & 3) ^ e] ^ v[9])
6e6d6c6b ^ 9f1cf72e = f1719b45
# (sum ^ y) + (key[(p & 3) ^ e] ^ v[9])
fc5623e0 + f1719b45 = edc7bf25
6e63 << 10 = 6e630000
# MZ2 = ((v[6] >> 2) ^ (v[9] << 5) + (v[6] << 3) ^ (v[9] >> 4)) ^ (sum ^ y) + (key[(p & 3) ^ e] ^ v[9])
eb21e004 ^ edc7bf25 = 6e65f21
7466 + 6e630000 = 6e637466
3230 << 10 = 32300000
3234 + 32300000 = 32303234
# z = v[5] + MZ2
6e65f21 + 58575655 = 5f3db576
key也就在输出中根据逻辑找到的
以下是解密脚本
exp1
#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX1 (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void btea(uint32_t *v, int n, uint32_t *key)
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) /* Coding Part */
{
rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++)
{
y = v[p+1];
//printf("%x \n", (p&3)^e);
//printf("%x \n", MX1);
z = v[p] += MX1;
//printf("%x ", z);
}
y = v[0];
z = v[n-1] += MX1;
}
while (--rounds);
}
else if (n < -1) /* Decoding Part */
{
n = -n;
rounds = 6 + 52/n;
sum = rounds*DELTA;
//printf("%d\n",rounds);
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--)
{
z = v[p-1];
y = v[p] -= MX1;
}
z = v[n-1];
y = v[0] -= MX1;
sum -= DELTA;
}
while (--rounds);
}
}
unsigned char cipher[]={ 0x5D, 0x45, 0xD5, 0xB9, 0x8C, 0x95, 0x9C, 0x38, 0x3B, 0xB1,
0x3E, 0x1E, 0x5F, 0xC8, 0xE8, 0xBB, 0x64, 0x38, 0x48, 0x69};
int main()
{
uint32_t *v = (uint32_t*)cipher;
uint32_t k[4]= {0x6e637466,0x62ef0ed,0xa78c0b4f,0x32303234};
int n= 5;
btea(v, -n, k);
unsigned char a;
for(int i = 0; i < 5; i++) {
//printf("%x ", v[i]);
}
for(int i=0;i<32;i++)
{
printf("%c", cipher[i]);
}
//NCTF{H4rd_VM_with_Go
return 0;
}
exp2
#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX1 (((z<<5^y>>2) + (y<<3^z>>4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void btea(uint32_t *v, int n, uint32_t *key)
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) /* Coding Part */
{
rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++)
{
y = v[p+1];
//printf("%x \n", (p&3)^e);
//printf("%x \n", MX1);
z = v[p] += MX1;
//printf("%x ", z);
}
y = v[0];
z = v[n-1] += MX1;
}
while (--rounds);
}
else if (n < -1) /* Decoding Part */
{
n = -n;
rounds = 6 + 52/n;
sum = rounds*DELTA;
//printf("%d\n",rounds);
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--)
{
z = v[p-1];
y = v[p] -= MX1;
}
z = v[n-1];
y = v[0] -= MX1;
sum -= DELTA;
}
while (--rounds);
}
}
unsigned char cipher[] = {
0xDE, 0x81, 0xD8, 0xAD, 0xC2, 0xC4, 0xA6, 0x32, 0x1C, 0xAB,
0x61, 0x3E, 0xCB, 0xFF, 0xEF, 0xF1, 0x27, 0x30, 0x7A, 0x16
};
int main()
{
uint32_t *v = (uint32_t*)cipher;
uint32_t k[4] = {0x32303234, 0xd6eb12c3, 0x9f1cf72e, 0x4e435446};
int n = 5;
btea(v, -n, k);
unsigned char a;
for(int i = 0; i < 5; i++) {
//printf("%x ", v[i]);
}
for(int i = 0; i < 20; i++)
{
printf("%c", cipher[i]);
}
//r0ut1n3_5fc4b0be7ad}
return 0;
}
NCTF{H4rd_VM_with_Gor0ut1n3_5fc4b0be7ad}
本题是参照0psu3战队的wp复现的。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1621925986@qq.com