提交人:太刀
superguesser | 动态调试
静态分析发现函数全部被混淆 在入口下断点步过函数直到进入被还原的函数 找到核心加密逻辑:
// positive sp value has been detected, the output may be wrong! __int64 __fastcall sub_401530() { __int64 stack; // rbp char v1; // zf __int64 (*v2)(void); // rax void *v3; // rsp __int64 v4; // rcx char v5; // of (loc_46EB33)(); _disable(); (loc_46EB77)(); (loc_46EBB4)(); if ( v1 ) JUMPOUT(0x401548i64); (loc_46EBF7)(); *(stack - 96) = 81; *(stack - 95) = 81; *(stack - 94) = 82; *(stack - 93) = 95; *(stack - 92) = 89; *(stack - 91) = 67; *(stack - 90) = 93; *(stack - 89) = 95; *(stack - 88) = 89; *(stack - 87) = 73; *(stack - 86) = 90; *(stack - 85) = 89; *(stack - 84) = 86; *(stack - 83) = 46; *(stack - 82) = 38; *(stack - 81) = 29; *(stack - 80) = 42; *(stack - 79) = 55; *(stack - 78) = 26; *(stack - 77) = 39; *(stack - 76) = 41; *(stack - 75) = 23; *(stack - 74) = 40; *(stack - 73) = 36; *(stack - 72) = 42; *(stack - 71) = 56; *(stack - 70) = 37; *(stack - 69) = 33; *(stack - 68) = 61; *(stack - 67) = 15; *(stack - 66) = 50; *(stack - 65) = 58; *(stack - 64) = 60; *(stack - 63) = 61; *(stack - 62) = 54; *(stack - 61) = 51; *(stack - 60) = 42; *(stack - 59) = 0; *(stack - 24) = (loc_46EC76)(stack - 96); *(stack - 25) = 51; v2 = (loc_46ECB3)(); __outbyte(0x2Fu, v2); *(stack - 26) = v2(); *(stack - 40) = *(stack - 24) - 1i64; (loc_46ECF6)(); (loc_46ED38)(); v3 = alloca((loc_46ED75)()); *(stack - 48) = alloc(); (scanf_0)(v4, *(stack - 48)); (loc_46EE32)(); (loc_46EEB1)(); if ( !v5 ) JUMPOUT(0x401651i64); while ( *(stack - 20) < *(stack - 24) ) *(*(stack - 48) + (*(stack - 20))++) ^= *(stack - 20) + *(stack - 25) + 17 * *(stack - 26);// i + ? + 17 * ?? if ( !(cmp)(*(stack - 48), stack - 96, *(stack - 24)) ) { (loc_46F030)(); JUMPOUT(0x4016E8i64); } (loc_46EF73)(); return (loc_46EFF3)(); }
动调发现stack-48
处存放的就是输入的flag 而只有这一处加密 由于不确定*(stack - 26)
的值是否因为反调试手段被修改 故用爆破方法解flag:
enc = [81, 81, 82, 95, 89, 67, 93, 95, 89, 73, 90, 89, 86, 46, 38, 29, 42, 55, 26, 39, 41, 23, 40, 36, 42, 56, 37, 33, 61, 15, 50, 58, 60, 61, 54, 51, 42] for ran in range(128): flag = "" for i in range(len(enc)): flag += chr((enc[i] ^ (i + 0x33 + 17 * ran)) & 0xff) if flag[:5] == "begin": print(flag) # begin{debugging_is_an_anathor_choice}
ezpython | 注入解法
用pyinstxtractor解包出的key和enc无法通过sm4解密得到flag 故使用原程序的环境进行解密 原程序反编译后主要逻辑:
from gmssl import sm4 from secrets import key, enc import base64 def pad_pkcs7(data): """PKCS#7填充""" padding_len = 16 - len(data) % 16 padding = bytes([padding_len] * padding_len) return data + padding def unpad_pkcs7(padded_data): """PKCS#7去填充""" padding_len = padded_data[-1] return padded_data[:-padding_len] class SM4: def __init__(self): self.gmsm4 = sm4.CryptSM4() def encryptSM4(self, encrypt_key, value): gmsm4 = self.gmsm4 gmsm4.set_key(encrypt_key.encode(), sm4.SM4_ENCRYPT) padded_value = pad_pkcs7(value.encode()) encrypt_value = gmsm4.crypt_ecb(padded_value) return base64.b64encode(encrypt_value) if __name__ == "__main__": flag = input("...") sm4_instance = SM4() flag_1 = sm4_instance.encryptSM4(key, flag) if flag_1 == enc: print("Success") else: print("Failed")
在powershell启动题目程序(用cmd或者直接启动貌似不行) 找到该程序的pid 使用de4py的PyShell功能将以下解密代码注入到程序:
def decryptSM4(self, encrypt_key, enc): gmsm4 = self.gmsm4 gmsm4.set_key(encrypt_key.encode(), sm4.SM4_DECRYPT) encrypt_value = base64.b64decode(enc) decrypt_value = gmsm4.crypt_ecb(encrypt_value) return unpad_pkcs7(decrypt_value).decode() SM4.decrypt = decryptSM4 sm4_new = SM4() print(sm4_new.decrypt(key, enc))
效果:
goforfun | go语言逆向
第一个加密的核心特征:
for ( i = 255; i >= 0; --i ) { if ( i >= 0x100 ) runtime_panicIndex(); *(box + i) = -1 - i; } count = 0; v7 = 0; while ( count < 256 ) { v8 = *(box + count); v9 = count; v10 = count - 12 * (((2863311531LL * count) >> 32) >> 3); if ( v10 >= 0xC ) runtime_panicIndex(); v7 += v35[v10] + v8; *(box + v9) = *(box + v7); *(box + v7) = v8; count = v9 + 1; } sub_462C00(&PRGA_result, box); flag_context = v4; lenth_of_context = v34; v26 = v11; main_PRGA(PRGA_result);
Sbox初始化 PRGA 但是不是普通的RC4加密 进入PRGA函数:
int __usercall main_PRGA@<eax>(char table) { int result; // eax signed int v2; // ecx unsigned int v3; // edx signed int v4; // ebx char v5; // bp char v6; // si char v7; // cl char v8; // [esp+12h] [ebp-2h] void *retaddr; // [esp+14h] [ebp+0h] BYREF if ( &retaddr <= *(*__readfsdword(runtime_tls_g) + 8) ) runtime_morestack_noctxt(); result = runtime_makeslice(&uint8, STACK[0x11C], STACK[0x11C]); v2 = STACK[0x11C]; v3 = STACK[0x118]; v4 = 0; v5 = 0; v6 = 0; while ( v2 > v4 ) { v7 = *(&table + (v5 + 1)); v8 = v7 + v6; *(&table + (v5 + 1)) = *(&table + (v7 + v6)); *(&table + (v7 + v6)) = v7; *(result + v4) = *(&table + (v7 + *(&table + (v5 + 1)))) ^ *(v3 + v4) ^ 0x2F; ++v4; v2 = STACK[0x11C]; ++v5; v6 = v8; } STACK[0x124] = result; STACK[0x128] = v2; STACK[0x12C] = v2; return result; }
动调发现v3
存放的就是输入的flag去除begin{}包裹的内容 所以加密只关心和其异或的东西 在最后异或步骤下状况断点 输出存放异或的数字的寄存器:
得到异或内容:
xor_key = [i ^ 0x2f for i in [132, 14, 121, 193, 41, 61, 231, 134, 147, 244, 180, 102, 100, 175, 25, 151, 133, 7, 230, 74, 200, 3, 55]]
最后一处加密的核心特征:
从64长度的表中按第二处加密得到的结果为下标取元素 最后和密文比较 猜测是换表base64
第二处加密:
v20 = main_byteArrayToBigInt(result, lenth_2); v22 = main_bigIntModToArray(str_head);
动调发现第一个函数的作用就是将第一处加密得到的结果按小端序储存为Go中的一种大整型数据(没有位数上限 能储存多大取决于计算机)
第二个函数:
__int128 __golang main_bigIntModToArray(int *a1) { int *mod_result_instanc; // eax int v2; // ecx int v3; // edx unsigned int i; // ebx int v5; // ebp int now_result; // ecx int origin_data; // eax unsigned int count_1; // ecx int add_; // edx int *final_procees; // ebx int *result_; // [esp+Ch] [ebp-6Ch] int *v12; // [esp+14h] [ebp-64h] unsigned int v13; // [esp+18h] [ebp-60h] int v14; // [esp+1Ch] [ebp-5Ch] int v15; // [esp+20h] [ebp-58h] unsigned int v16; // [esp+24h] [ebp-54h] unsigned int v17; // [esp+28h] [ebp-50h] int v18; // [esp+28h] [ebp-50h] int mod_num_2; // [esp+2Ch] [ebp-4Ch] BYREF int mod_num; // [esp+30h] [ebp-48h] BYREF int v21; // [esp+44h] [ebp-34h] int v22[4]; // [esp+48h] [ebp-30h] BYREF int mod_n[4]; // [esp+58h] [ebp-20h] BYREF int be_moded_instanc[4]; // [esp+68h] [ebp-10h] BYREF void *retaddr; // [esp+78h] [ebp+0h] BYREF __int128 result; // [esp+80h] [ebp+8h] if ( &retaddr <= *(*__readfsdword(runtime_tls_g) + 8) ) runtime_morestack_noctxt(); mod_result_instanc = a1; v2 = 0; v3 = 0; for ( i = 0; ; i = v16 ) { if ( mod_result_instanc[2] ) v5 = *mod_result_instanc ? -1 : 1; else v5 = 0; if ( v5 <= 0 ) break; v17 = v2; v21 = v3; LOBYTE(be_moded_instanc[0]) = 0; memset(&be_moded_instanc[1], 0, 12); mod_num = 64; LOBYTE(mod_n[0]) = 0; mod_n[1] = &mod_num; mod_n[2] = 1; mod_n[3] = 1; result_ = math_big__Int_Mod(be_moded_instanc, mod_result_instanc, mod_n); if ( result_[2] ) now_result = *result_[1]; else now_result = 0; if ( *result_ ) origin_data = -now_result; else origin_data = now_result; count_1 = i + 1; add_ = v17; if ( v17 < i + 1 ) { v15 = origin_data; v12 = runtime_growslice(v21, i + 1, v17, 1, &int); count_1 = v13; final_procees = v12; add_ = v14; origin_data = v15; } else { final_procees = v21; } v21 = final_procees; v16 = count_1; v18 = add_; final_procees[count_1 - 1] = origin_data; mod_num_2 = 0x40; LOBYTE(v22[0]) = 0; v22[1] = &mod_num_2; v22[2] = 1; v22[3] = 1; math_big__Int_Div(a1, a1, v22); mod_result_instanc = a1; v3 = v21; v2 = v18; } *&result = __PAIR64__(i, v3); DWORD2(result) = v2; return result; }
核心是其中的大整型取模和大整型除法 动调发现取模和除法都是对第一个函数得到的大整型进行 另一个操作数是0x40
也就是result = big_int & 0xFFFFFF, big_int >> 6
符合之前base64的猜测(但是直接用base64解出来不对 所以自己写解密脚本):
xor_key = [i ^ 0x2f for i in [132, 14, 121, 193, 41, 61, 231, 134, 147, 244, 180, 102, 100, 175, 25, 151, 133, 7, 230, 74, 200, 3, 55]] enc = ["8G+cazk2jqb7w01CtoKH4FsrgR3vVmQ9pPhXLAleOd/nB6DfIxMWYiUZ5SEJyNuT".index(i) for i in"HZ0sMJXqxHgUb2b9RNg+1xw"] enc = [bin(i).replace("0b", "").zfill(6) for i in enc][::-1] big_int = int("".join(enc), 2) flag = [] while big_int > 0: flag.append(big_int & 0xff) big_int >>= 8 flag = flag[::-1] for i in range(len(flag)): print(chr(flag[i] ^ xor_key[i]), end="") # go_a_nice_journey
not main | 反调试
IDA识别出的主函数:
int __cdecl main(int argc, const char **argv, const char **envp) { unsigned int v3; // ecx __int32 *pt_input1; // edi unsigned __int32 now; // edx int sum; // ebx unsigned __int32 next; // esi int v8; // edi __int32 *pt_input3; // ecx __int32 *v10; // edx unsigned int v11; // esi bool v12; // cf unsigned int v13; // edx int v14; // eax int v16; // [esp-4h] [ebp-2Ch] __int32 *pt_input2; // [esp+Ch] [ebp-1Ch] __int128 v18; // [esp+10h] [ebp-18h] BYREF int v19; // [esp+20h] [ebp-8h] sub_141930(std::cin); v3 = strlen(enc); if ( v3 == 0x1A ) { pt_input1 = enc; pt_input2 = enc; do { now = *pt_input1; sum = 0; // TEA next = pt_input1[1]; v8 = 32; do { sum -= 0x61C88647; now += ((next >> 5) + 97) ^ (16 * next + 102) ^ (sum + next); next += ((now >> 5) + 101) ^ (16 * now + 107) ^ (sum + now); --v8; } while ( v8 ); *pt_input2 = now; pt_input2[1] = next; pt_input1 = pt_input2 + 2; pt_input2 = pt_input1; } while ( pt_input1 < &debug_flag_1 ); pt_input3 = enc; v10 = to_cmp; v11 = 28; while ( *pt_input3 == *v10 ) { ++pt_input3; ++v10; v12 = v11 < 4; v11 -= 4; if ( v12 ) { v18 = xmmword_143220; LOBYTE(v19) = 19; v13 = 0; v3 = strlen(&v18); if ( v3 ) { do *(&v18 + v13++) ^= 0x13u; while ( v13 < &v18 + strlen(&v18) + 1 - (&v18 + 1) ); } goto LABEL_11; } } } else { LABEL_11: // fail v14 = sub_141600(v3, sub_141830); std::ostream::operator<<(v14, v16); } return 0; }
包含一个TEA 但是解出来是假flag while ( pt_input1 < &debug_flag_1 );
这一行对flag交叉引用到达一个异常处理函数:
int sub_141010() { uint8_t BeingDebugged; // al BeingDebugged = NtCurrentPeb()->BeingDebugged; debug_flag_1 = BeingDebugged != 0; if ( BeingDebugged ) AddVectoredExceptionHandler(1u, Handler); return atexit(sub_142AE0); }
Handler
应该就是程序正常运行过程中主函数触发异常后执行的处理函数:
LONG __userpurge Handler@<eax>(int a1@<edi>, struct _EXCEPTION_POINTERS *ExceptionInfo) { DWORD ExceptionCode; // eax PCONTEXT ContextRecord; // eax int sum; // ecx unsigned __int32 temp; // eax unsigned int v7; // ebx unsigned int i; // edi bool v9; // zf _DWORD *real_enc; // edx __int32 *v11; // ecx unsigned int v12; // esi bool v13; // cf unsigned int j; // edx int v15; // eax int v16; // [esp-10h] [ebp-44h] unsigned int addr_13503C; // [esp+4h] [ebp-30h] int v19; // [esp+8h] [ebp-2Ch] int v20; // [esp+Ch] [ebp-28h] int temp_2; // [esp+10h] [ebp-24h] int key[4]; // [esp+14h] [ebp-20h] int v23[3]; // [esp+24h] [ebp-10h] BYREF ExceptionCode = ExceptionInfo->ExceptionRecord->ExceptionCode; if ( ExceptionCode == -2147483645 ) { ContextRecord = ExceptionInfo->ContextRecord; dword_145038 = 0; ++ContextRecord->Eip; return -1; } else if ( ExceptionCode == 0xC0000094 ) { return 0; } else { key[0] = 116; addr_13503C = to_cmp ^ ::addr_13503C; sum = 0; ::addr_13503C ^= to_cmp; temp = enc_7_; key[1] = 114; key[2] = 117; key[3] = 101; v19 = 12; temp_2 = enc_7_; do { v20 = sum - 0x61C88647; v7 = ((sum - 0x61C88647) >> 2) & 3; for ( i = 0; i < 7; ++i ) { enc[i] += ((v20 ^ enc_1_[i]) + (temp_2 ^ key[v7 ^ i & 3])) ^ (((16 * temp_2) ^ (enc_1_[i] >> 3)) + ((temp >> 5) ^ (4 * enc_1_[i]))); temp = enc[i]; temp_2 = temp; } sum -= 0x61C88647; temp = (((v20 ^ enc[0]) + (temp ^ key[v7 ^ i & 3])) ^ (((16 * temp) ^ (enc[0] >> 3)) + ((temp >> 5) ^ (4 * enc[0])))) + enc_7_; v9 = v19-- == 1; temp_2 = temp; enc_7_ = temp; } while ( !v9 ); real_enc = addr_13503C; v11 = enc; v12 = 28; while ( *v11 == *real_enc ) { ++v11; ++real_enc; v13 = v12 < 4; v12 -= 4; if ( v13 ) { v23[0] = 862354538; v23[1] = 862418548; v23[2] = 322070394; for ( j = 0; j < strlen(v23); ++j ) *(v23 + j) ^= 0x13u; v15 = sub_141600(sub_141830, a1); std::ostream::operator<<(v15, v16); break; } } ExceptionInfo->ContextRecord->Ecx = 1; return -1; } }
包含一个XXTEA加密 exp:
#include <stdio.h> #include <stdlib.h> int delta = 0x61C88647; unsigned __int32 enc[] = { 0xCFBE0F1B, 0x5F3083F, 0x4220E43B, 0x3383AFEE, 0xFA3237CE, 0xECADA66E, 0xA8D47CA7, 0xEFC51077 }; int key[4] = {116, 114, 117, 101}; //TEA decrypt void main(){ int count = 11; unsigned int sum = -12 * 0x61C88647; int delta = 0x61C88647; do{ int j = (sum >> 2) & 3; enc[7] -= (((sum ^ enc[0]) + (enc[6] ^ key[j ^ 7 & 3])) ^ (((16 * enc[6]) ^ (enc[0] >> 3)) + ((enc[6] >> 5) ^ (4 * enc[0])))); for(int i = 6; i >= 1; i--){ enc[i] -= (((sum ^ enc[i + 1]) + (enc[i - 1] ^ key[j ^ i & 3])) ^ (((16 * enc[i - 1]) ^ (enc[i + 1] >> 3)) + ((enc[i - 1] >> 5) ^ (4 * enc[i + 1])))); } enc[0] -= (((sum ^ enc[1]) + (enc[7] ^ key[j ^ 0 & 3])) ^ (((16 * enc[7]) ^ (enc[1] >> 3)) + ((enc[7] >> 5) ^ (4 * enc[1])))); sum += delta; for(int i = 0; i < 8; i++){ } }while(count--); for(int i = 0; i < 8; i += 2){ sum = -32 * 0x61C88647; for(int _ = 0; _ < 32; _++){ enc[i + 1] -= ((enc[i] >> 5) + 101) ^ (16 * enc[i] + 107) ^ (sum + enc[i]); enc[i] -= ((enc[i + 1] >> 5) + 97) ^ (16 * enc[i + 1] + 102) ^ (sum + enc[i + 1]); sum += delta; } } for(int i = 0; i < 8; i++){ for(int j = 0; j < 4; j++){ printf("%c", (enc[i] >> (8 * j)) & 0xff); } } // begin{not_main_is_matter!} }
出题人的密码是什么 | 不知道什么加密 | 混淆
最后的比较函数:
看起来是对控制流进行了混淆 先猜测就是按顺序一个一个对比 主函数开头就加了反调试:
.text:00AC8540 8B F4 mov esi, esp .text:00AC8542 FF 15 00 C0 B3 00 call ds:IsDebuggerPresent .text:00AC8542 .text:00AC8548 3B F4 cmp esi, esp .text:00AC854A E8 6E AA FF FF call j___RTC_CheckEsp .text:00AC854A .text:00AC854F 85 C0 test eax, eax .text:00AC8551 75 11 jnz short loc_AC8564 ; Keypatch modified this from: .text:00AC8551 ; jz short loc_438564 .text:00AC8551 ; Keypatch modified this from: .text:00AC8551 ; jz short loc_D38564 .text:00AC8551 .text:00AC8553 8B F4 mov esi, esp .text:00AC8555 6A 00 push 0 ; uExitCode .text:00AC8557 FF 15 08 C0 B3 00 call ds:ExitProcess
这里patch掉 接下来输入完flag后有很多无用函数干扰分析 没用的函数标记一下 在唯一一个有用的分支找到两个加密函数:
j__gets_s(passw, 0x64u); fzwufunc(); fzwufunc2(); j_fzwu(); fzwufunc(); sub_AC125D(); j_fzwu__(); ... int sub_D78120() { __CheckForDebuggerJustMyCode(byte_B3D0F4); j_procees_func1(); j_procees_func2(); return 0; }
第二个加密函数:
int procees_func2() { int result; // eax int i; // [esp+D0h] [ebp-8h] result = __CheckForDebuggerJustMyCode(&byte_B3D0F4); for ( i = 0; i < 48; ++i ) { final_[i] = (passw[i] + 5) ^ 0x25; result = i + 1; } return result; }
对第一个函数加密后的数据进行加法和异或
第一个加密函数:
int procees_func1() { int v0; // edx int result; // eax __int64 v2; // [esp+D0h] [ebp-58h] size_t v3; // [esp+ECh] [ebp-3Ch] int j; // [esp+F8h] [ebp-30h] int i; // [esp+104h] [ebp-24h] __int64 v6; // [esp+110h] [ebp-18h] char *v7; // [esp+120h] [ebp-8h] __CheckForDebuggerJustMyCode(byte_B3D0F4); v3 = j__strlen(user); if ( v3 ) j__srand(byte_B39FD7[v3]); else j__srand(0x123456u); v0 = j__rand() % 7; // v0 = 7 result = dword_B39000[2 * v0]; LODWORD(v2) = result; HIDWORD(v2) = dword_B39004[2 * v0]; // v2 = 0x33077D for ( i = 0; i < 6; ++i ) { v7 = &passw[8 * i]; v6 = *v7; for ( j = 0; j < 64; ++j ) { if ( v6 < 0 ) v6 = v2 ^ (2 * v6); else v6 *= 2i64; } *v7 = v6; result = i + 1; } return result; }
对输入的flag进行32位小端序储存 然后根据当前数据块的正负(最高位)选择进行左移1位还是左移后再异或 这个异或会使左移后最后一位由0变成1 由此储存因左移丢失的数据 据此写出exp 发现那个控制流混淆确实就是一位一位对比:
#include <stdio.h> #include <stdlib.h> int main(){ unsigned __int8 enc[] = {0xB4, 0xBB, 0xD8, 0xEB, 0xD0, 0x6E, 0xAB, 0xCA, 0x65, 0x8E, 0x4B, 0xE9, 0x4D, 0xD4, 0x4A, 0xF3, 0x7D, 0x29, 0xC2, 0xF9, 0x95, 0x89, 0xA4, 0x85, 0x9D, 0xCD, 0xDF, 0x77, 0xFD, 0x45, 0xCB, 0x5D, 0x7D, 0xFD, 0x93, 0x4B, 0xBC, 0xF6, 0x7C, 0xF3, 0x24, 0x42, 0xF5, 0xD2, 0xDD, 0xE3, 0x56, 0xAE}; __int64 d = 0x000000000033077D; for(int i = 0; i < 48; i++){ enc[i] ^= 0x25; enc[i] -= 5; } unsigned __int64 enc_[6]; for(int i = 0; i < 6; i++){ enc_[i] = 0; for(int j = 0; j < 8; j++){ enc_[i] |= (__int64)enc[8 * i + j] << (j * 8); } } for(int i = 0; i < 8; i++){ for(int j = 0; j < 64; ++j){ if(enc_[i] & 1){ enc_[i] ^= d; enc_[i] >>= 1; enc_[i] |= (__int64)(0x8000000000000000); } else{ enc_[i] >>= 1; } } } // save the data back to enc with big-ending for(int i = 0; i < 8; i++){ for(int j = 0; j < 8; j++){ enc[i * 8 + j] = (enc_[i] >> (j * 8)) & 0xFF; } } for(int i = 0; i < 48; i++){ printf("%c", enc[i]); } // begin{Th1s_reverse_pr0blem_may_t@ke_some_time#!} }
俄语学习 | 防静态分析
主要加密:
int sub_1A1F80() { int v0; // eax int result; // eax int k; // [esp+D0h] [ebp-54h] size_t j; // [esp+DCh] [ebp-48h] size_t i; // [esp+E8h] [ebp-3Ch] char Str[44]; // [esp+F4h] [ebp-30h] BYREF __CheckForDebuggerJustMyCode(&unk_22F0F4); qmemcpy(Str, cource, 0x25u); for ( i = 0; i <= j__strlen(Str); ++i ) sourc_key[i] = Str[i] - 0x72; for ( j = 0; j <= j__strlen(sourc_key); ++j ) key[j] = sourc_key[j]; v0 = j__strlen(sourc_key); result = sub_19B6D0(table, sourc_key, v0); for ( k = 0; k < 256; ++k ) { copy_table[k] = table[k]; result = k + 1; } return result; }
其中table初始化是干扰分析的 后面并不会用到 主要加密方式就是根据key对flag进行加减运算 以下是exp:
int sub_1A1F80() { int v0; // eax int result; // eax int k; // [esp+D0h] [ebp-54h] size_t j; // [esp+DCh] [ebp-48h] size_t i; // [esp+E8h] [ebp-3Ch] char Str[44]; // [esp+F4h] [ebp-30h] BYREF __CheckForDebuggerJustMyCode(&unk_22F0F4); qmemcpy(Str, cource, 0x25u); for ( i = 0; i <= j__strlen(Str); ++i ) sourc_key[i] = Str[i] - 0x72; for ( j = 0; j <= j__strlen(sourc_key); ++j ) key[j] = sourc_key[j]; v0 = j__strlen(sourc_key); result = sub_19B6D0(table, sourc_key, v0); for ( k = 0; k < 256; ++k ) { copy_table[k] = table[k]; result = k + 1; } return result; } # flag{Russian_is_so_easy}
红白机 | 简单虚拟机
使用的是6502虚拟机 直接模拟其运行(或者分析后手画也行) 这里已经用文本编辑器替换过原来的6502指令
from PIL import Image import numpy as np import matplotlib.pyplot as plt flag = np.array(Image.open('flag.png')) with open("6502.txt") as f: now_color = 255 offset = 0 while offset <= 0x3FF: flag[int(offset / 32), offset % 32] = now_color offset += 1 offset = 1 lines = f.readlines() count = 0 for i in range(len(lines)): lines[i] = lines[i].replace("\n", "") for line in lines[36:]: if line[:8] == "color = ": now_color = int(line[8:], 16) * 255 if line[:10] == "load color": flag[int((offset + int(line[15:18], 16) - 0x200) / 32), offset % 32] = now_color count += 1 print(now_color, offset, int(offset / 32), offset % 32, count) if line == "offset += 1": offset += 1 if line[:8] == "offset =": offset = int(line[8:], 16) plt.figure("flag") plt.imshow(flag) plt.axis('off') plt.show()
stick game | js混淆
js中游戏的主要逻辑被混淆:
用网站反混淆:
直接找到flag
xor
主要逻辑就是将flag分前后两半加密 用key正着异或一遍再倒着抑或一遍 再交换前后使用的key再重复上述过程 exp:
key = [52, 49, 56, 48, 51, 56, 55, 51, 54, 50, 53, 57, 48, 49, 51, 54, 51, 48, 57, 50, 54, 48, 54, 54, 51, 50, 55, 56, 55, 57, 52, 55] key1 = [54, 51, 50, 57, 48, 55, 57, 52, 50, 48, 55, 55, 49, 53, 53, 56, 55, 54, 55, 57, 54, 50, 49, 51, 56, 54, 55, 51, 53, 48, 48, 48] hbkey = key[0:16] + [0] qmkey = key[16:32] + [0] enc = [ord(i) for i in "`agh{^bvuwTooahlYocPtmyiijj|ek'p"] qm = enc[0:16] hb = enc[16:32] for i in range(16): qm[i] ^= qmkey[16 - i] qm[i] ^= hbkey[16 - i] hb[i] ^= hbkey[16 - i] hb[i] ^= qmkey[16 - i] for i in range(16): qm[i] ^= qmkey[i] qm[i] ^= hbkey[i] hb[i] ^= hbkey[i] hb[i] ^= qmkey[i] hbkey = key1[0:16] + [0] qmkey = key1[16:32] + [0] for i in range(16): qm[i] ^= qmkey[16 - i] qm[i] ^= hbkey[16 - i] hb[i] ^= hbkey[16 - i] hb[i] ^= qmkey[16 - i] for i in range(16): qm[i] ^= qmkey[i] qm[i] ^= hbkey[i] hb[i] ^= hbkey[i] hb[i] ^= qmkey[i] flag = "".join([chr(i) for i in qm + hb]) print(flag) # flag{Virus_gonna_be_terminated!}
babyvm | vmre
模拟虚拟机运行过程 :
# emulate the procees of vm from struct import unpack with open("opcode.txt", "w") as opcode: with open("opcode.vm", 'rb') as opcode_file: with open("memory.vm", 'rb') as memory: all_memory = [] input_text = [] output_text = [] data = memory.read(4) while(data): all_memory.append(unpack("<I", data)[0]) data = memory.read(4) now_op = opcode_file.read(4) in_pointer = 0 out_pointer = 0 count = 0 count_sum = 0 while(now_op): print(unpack("<I", now_op)[0]) if unpack("<I", now_op)[0] == 1: now_op = opcode_file.read(3 * 4) all_memory[unpack("<I", now_op[0:4])[0]] = all_memory[unpack("<I", now_op[4:8])[0]] + all_memory[unpack("<I", now_op[8:12])[0]] now_op = opcode_file.read(4) continue if unpack("<I", now_op)[0] == 2: now_op = opcode_file.read(3 * 4) opcode.write("sum[" + str(count_sum - 8) + "] == " + str(all_memory[unpack("<I", now_op[8:12])[0]]) + "\n") count_sum += 1 all_memory[unpack("<I", now_op[0:4])[0]] = all_memory[unpack("<I", now_op[4:8])[0]] - all_memory[unpack("<I", now_op[8:12])[0]] now_op = opcode_file.read(4) continue if unpack("<I", now_op)[0] == 3: now_op = opcode_file.read(3 * 4) opcode.write("key[" + str(int(count / 20)) +"][" + str(count % 20) + "] == " + str(all_memory[unpack("<I", now_op[8:12])[0]]) + ", ") count += 1 all_memory[unpack("<I", now_op[0:4])[0]] = all_memory[unpack("<I", now_op[4:8])[0]] * all_memory[unpack("<I", now_op[8:12])[0]] now_op = opcode_file.read(4) continue if unpack("<I", now_op)[0] == 4: now_op = opcode_file.read(3 * 4) print("mem[" + str(unpack("<I", (now_op[0:4]))[0]) + "] = mem[" + str(unpack("<I", now_op[4:8])[0]) + "] / mem[" + str(unpack("<I", now_op[8:12])[0]) + "]") opcode.write("mem[" + str(unpack("<I", (now_op[0:4]))[0]) + "] = mem[" + str(unpack("<I", now_op[4:8])[0]) + "] / mem[" + str(unpack("<I", now_op[8:12])[0]) + "]\n") print("mem[" + str(unpack("<I", now_op[0:4])[0]) + "] = " + str(all_memory[unpack("<I", now_op[0:4])[0]]), end = ", ") opcode.write("mem[" + str(unpack("<I", now_op[0:4])[0]) + "] = " + str(all_memory[unpack("<I", now_op[0:4])[0]]) + "\n") print("mem[" + str(unpack("<I", now_op[4:8])[0]) + "] = " + str(all_memory[unpack("<I", now_op[4:8])[0]]), end = ", ") opcode.write("mem[" + str(unpack("<I", now_op[4:8])[0]) + "] = " + str(all_memory[unpack("<I", now_op[4:8])[0]]) + "\n") print("mem[" + str(unpack("<I", now_op[8:12])[0]) + "] = " + str(all_memory[unpack("<I", now_op[8:12])[0]])) opcode.write("mem[" + str(unpack("<I", now_op[8:12])[0]) + "] = " + str(all_memory[unpack("<I", now_op[8:12])[0]]) + "\n") all_memory[unpack("<I", now_op[0:4])[0]] = all_memory[unpack("<I", now_op[4:8])[0]] / all_memory[unpack("<I", now_op[8:12])[0]] now_op = opcode_file.read(4) continue #reset the in pointer if unpack("<I", now_op)[0] == 5: in_pointer = 0 print("in_pointer = 0") opcode.write("in_pointer = 0\n") now_op = opcode_file.read(4) continue #reset the out pointer if unpack("<I", now_op)[0] == 6: out_pointer = 0 print("out_pointer = 0") opcode.write("out_pointer = 0\n") now_op = opcode_file.read(4) continue #pop-in if unpack("<I", now_op)[0] == 7: now_op = opcode_file.read(4) arg = opcode_file.read(4) print("from input[" + hex(in_pointer) + "] copy " + str(unpack("<I", arg)[0]) + " bytes to mem[" + str(unpack("<I", now_op)[0]) + "]") opcode.write("from input[" + hex(in_pointer) + "] copy " + str(unpack("<I", arg)[0]) + " bytes to mem[" + str(unpack("<I", now_op)[0]) + "]\n") for i in range(unpack("<I", arg)[0]): try: all_memory[unpack("<I", now_op)[0] + i] = input_text[in_pointer] in_pointer += 1 except: break now_op = opcode_file.read(4) continue #pop-out if unpack("<I", now_op)[0] == 8: now_op = opcode_file.read(4) arg = opcode_file.read(4) print("from mem[" + str(unpack("<I", now_op)[0]) + "] copy " + str(unpack("<I", arg)[0]) + " bytes to output[" + hex(out_pointer) + "]") opcode.write("from mem[" + str(unpack("<I", now_op)[0]) + "] copy " + str(unpack("<I", arg)[0]) + " bytes to output[" + hex(out_pointer) + "]\n") for i in range(unpack("<I", arg)[0]): output_text.append(all_memory[unpack("<I", now_op)[0] + i]) out_pointer += 1 now_op = opcode_file.read(4) continue #read_buffer if unpack("<I", now_op)[0] == 9: now_op = opcode_file.read(4) print("get_user_input and write in", unpack("<I", now_op)[0]) opcode.write("get_user_input and write in " + str(unpack("<I", now_op)[0]) + "\n") input_text = [ord(c) for c in input()] for i in range(len(input_text)): all_memory[unpack("<I", now_op)[0] + i] = input_text[i] now_op = opcode_file.read(4) continue #write_buffer if unpack("<I", now_op)[0] == 10: now_op = opcode_file.read(4) print("print signal(correct or not)") opcode.write("print signal(correct or not)\n") print("".join([chr(c) for c in output_text])) opcode.write("".join([chr(c) for c in output_text]) + "\n") now_op = opcode_file.read(4) continue #jump if unpack("<I", now_op)[0] == 11: now_op = opcode_file.read(4) arg = opcode_file.read(4) now_mem = all_memory[unpack("<I", arg)[0]] # if (arg and not(now_mem)): # print("goto " + hex(unpack("<I", now_op)[0])) # opcode_file.seek(unpack("<I", now_op)[0]) # now_op = opcode_file.read(4) # continue # else: print("not jump") opcode.write("not jump\n") for _ in range(unpack("<I", now_op)[0] - 1): now_op = opcode_file.read(4) now_op = opcode_file.read(4) continue #not-jump if unpack("<I", now_op)[0] == 12: now_op = opcode_file.read(4) arg = opcode_file.read(4) now_mem = all_memory[unpack("<I", arg)[0]] # if (arg and (now_mem)): # print("goto " + hex(unpack("<I", now_op)[0])) # opcode_file.seek(unpack("<I", now_op)[0]) # now_op = opcode_file.read(4) # continue # else: print("not jump") opcode.write("not jump\n") for _ in range(unpack("<I", now_op)[0] - 2): now_op = opcode_file.read(4) now_op = opcode_file.read(4) continue #get-lenth-of-input if unpack("<I", now_op)[0] == 13: now_op = opcode_file.read(4) arg = opcode_file.read(4) print("mem[" + str(unpack("<I", arg)[0]) + "] = len(mem[" + str(unpack("<I", now_op)[0]) +"])") opcode.write("mem[" + str(unpack("<I", arg)[0]) + "] = len(mem[" + str(unpack("<I", now_op)[0]) +"])\n") all_memory[unpack("<I", arg)[0]] = len(input_text) now_op = opcode_file.read(4) continue else: print("error") break
这里对所有flag错误导致的跳转进行剪枝 让虚拟机一直跑到结束以获得完整的运行过程 发现是用输入的20个字节构造20元方程组(所以这里的输出op的脚本进行了简化 只输出每一项的系数和0次项) 得到增广矩阵:
key[0][0] == 115, key[0][1] == 26, key[0][2] == 128, key[0][3] == 200, key[0][4] == 21, key[0][5] == 234, key[0][6] == 172, key[0][7] == 152, key[0][8] == 39, key[0][9] == 71, key[0][10] == 55, key[0][11] == 28, key[0][12] == 105, key[0][13] == 42, key[0][14] == 75, key[0][15] == 63, key[0][16] == 114, key[0][17] == 205, key[0][18] == 2, key[0][19] == 222, sum[0] == 217114 not jump key[1][0] == 212, key[1][1] == 148, key[1][2] == 17, key[1][3] == 74, key[1][4] == 87, key[1][5] == 253, key[1][6] == 250, key[1][7] == 136, key[1][8] == 89, key[1][9] == 211, key[1][10] == 49, key[1][11] == 26, key[1][12] == 115, key[1][13] == 88, key[1][14] == 181, key[1][15] == 195, key[1][16] == 237, key[1][17] == 10, key[1][18] == 119, key[1][19] == 121, sum[1] == 270581 not jump key[2][0] == 229, key[2][1] == 172, key[2][2] == 230, key[2][3] == 123, key[2][4] == 245, key[2][5] == 127, key[2][6] == 119, key[2][7] == 157, key[2][8] == 208, key[2][9] == 159, key[2][10] == 37, key[2][11] == 32, key[2][12] == 5, key[2][13] == 207, key[2][14] == 145, key[2][15] == 75, key[2][16] == 251, key[2][17] == 60, key[2][18] == 135, key[2][19] == 125, sum[2] == 291585 not jump key[3][0] == 181, key[3][1] == 83, key[3][2] == 66, key[3][3] == 43, key[3][4] == 85, key[3][5] == 198, key[3][6] == 89, key[3][7] == 205, key[3][8] == 114, key[3][9] == 221, key[3][10] == 105, key[3][11] == 145, key[3][12] == 155, key[3][13] == 91, key[3][14] == 123, key[3][15] == 48, key[3][16] == 76, key[3][17] == 64, key[3][18] == 141, key[3][19] == 22, sum[3] == 234325 not jump key[4][0] == 211, key[4][1] == 225, key[4][2] == 204, key[4][3] == 55, key[4][4] == 107, key[4][5] == 76, key[4][6] == 7, key[4][7] == 39, key[4][8] == 199, key[4][9] == 84, key[4][10] == 167, key[4][11] == 62, key[4][12] == 219, key[4][13] == 54, key[4][14] == 6, key[4][15] == 144, key[4][16] == 55, key[4][17] == 98, key[4][18] == 186, key[4][19] == 116, sum[4] == 240502 not jump key[5][0] == 149, key[5][1] == 163, key[5][2] == 127, key[5][3] == 186, key[5][4] == 46, key[5][5] == 118, key[5][6] == 247, key[5][7] == 194, key[5][8] == 9, key[5][9] == 165, key[5][10] == 169, key[5][11] == 224, key[5][12] == 68, key[5][13] == 129, key[5][14] == 54, key[5][15] == 15, key[5][16] == 134, key[5][17] == 39, key[5][18] == 185, key[5][19] == 248, sum[5] == 277604 not jump key[6][0] == 245, key[6][1] == 159, key[6][2] == 64, key[6][3] == 241, key[6][4] == 163, key[6][5] == 116, key[6][6] == 4, key[6][7] == 15, key[6][8] == 126, key[6][9] == 170, key[6][10] == 10, key[6][11] == 110, key[6][12] == 251, key[6][13] == 169, key[6][14] == 252, key[6][15] == 99, key[6][16] == 199, key[6][17] == 188, key[6][18] == 149, key[6][19] == 72, sum[6] == 286168 not jump key[7][0] == 233, key[7][1] == 38, key[7][2] == 197, key[7][3] == 105, key[7][4] == 202, key[7][5] == 2, key[7][6] == 22, key[7][7] == 225, key[7][8] == 189, key[7][9] == 166, key[7][10] == 239, key[7][11] == 220, key[7][12] == 70, key[7][13] == 98, key[7][14] == 194, key[7][15] == 129, key[7][16] == 27, key[7][17] == 236, key[7][18] == 159, key[7][19] == 62, sum[7] == 290450 not jump key[8][0] == 152, key[8][1] == 67, key[8][2] == 72, key[8][3] == 35, key[8][4] == 12, key[8][5] == 55, key[8][6] == 139, key[8][7] == 4, key[8][8] == 169, key[8][9] == 142, key[8][10] == 135, key[8][11] == 122, key[8][12] == 3, key[8][13] == 166, key[8][14] == 139, key[8][15] == 62, key[8][16] == 23, key[8][17] == 92, key[8][18] == 11, key[8][19] == 136, sum[8] == 179355 not jump key[9][0] == 96, key[9][1] == 141, key[9][2] == 38, key[9][3] == 124, key[9][4] == 139, key[9][5] == 43, key[9][6] == 15, key[9][7] == 119, key[9][8] == 30, key[9][9] == 252, key[9][10] == 255, key[9][11] == 123, key[9][12] == 223, key[9][13] == 200, key[9][14] == 21, key[9][15] == 117, key[9][16] == 231, key[9][17] == 9, key[9][18] == 239, key[9][19] == 222, sum[9] == 272487 not jump key[10][0] == 249, key[10][1] == 91, key[10][2] == 66, key[10][3] == 21, key[10][4] == 121, key[10][5] == 146, key[10][6] == 5, key[10][7] == 180, key[10][8] == 6, key[10][9] == 80, key[10][10] == 112, key[10][11] == 255, key[10][12] == 239, key[10][13] == 17, key[10][14] == 39, key[10][15] == 254, key[10][16] == 153, key[10][17] == 118, key[10][18] == 47, key[10][19] == 217, sum[10] == 249816 not jump key[11][0] == 84, key[11][1] == 96, key[11][2] == 190, key[11][3] == 188, key[11][4] == 255, key[11][5] == 181, key[11][6] == 188, key[11][7] == 124, key[11][8] == 47, key[11][9] == 70, key[11][10] == 201, key[11][11] == 160, key[11][12] == 126, key[11][13] == 210, key[11][14] == 236, key[11][15] == 22, key[11][16] == 120, key[11][17] == 181, key[11][18] == 197, key[11][19] == 69, sum[11] == 305636 not jump key[12][0] == 51, key[12][1] == 173, key[12][2] == 216, key[12][3] == 143, key[12][4] == 41, key[12][5] == 174, key[12][6] == 184, key[12][7] == 189, key[12][8] == 111, key[12][9] == 133, key[12][10] == 79, key[12][11] == 36, key[12][12] == 99, key[12][13] == 140, key[12][14] == 120, key[12][15] == 144, key[12][16] == 80, key[12][17] == 231, key[12][18] == 187, key[12][19] == 107, sum[12] == 276217 not jump key[13][0] == 173, key[13][1] == 39, key[13][2] == 151, key[13][3] == 161, key[13][4] == 139, key[13][5] == 233, key[13][6] == 143, key[13][7] == 205, key[13][8] == 170, key[13][9] == 125, key[13][10] == 209, key[13][11] == 54, key[13][12] == 128, key[13][13] == 134, key[13][14] == 55, key[13][15] == 246, key[13][16] == 157, key[13][17] == 57, key[13][18] == 42, key[13][19] == 195, sum[13] == 294166 not jump key[14][0] == 5, key[14][1] == 49, key[14][2] == 235, key[14][3] == 8, key[14][4] == 84, key[14][5] == 9, key[14][6] == 219, key[14][7] == 90, key[14][8] == 109, key[14][9] == 164, key[14][10] == 38, key[14][11] == 159, key[14][12] == 218, key[14][13] == 214, key[14][14] == 22, key[14][15] == 205, key[14][16] == 7, key[14][17] == 57, key[14][18] == 210, key[14][19] == 131, sum[14] == 237236 not jump key[15][0] == 107, key[15][1] == 67, key[15][2] == 107, key[15][3] == 141, key[15][4] == 129, key[15][5] == 250, key[15][6] == 97, key[15][7] == 3, key[15][8] == 26, key[15][9] == 215, key[15][10] == 119, key[15][11] == 213, key[15][12] == 255, key[15][13] == 183, key[15][14] == 229, key[15][15] == 1, key[15][16] == 27, key[15][17] == 9, key[15][18] == 88, key[15][19] == 59, sum[15] == 242008 not jump key[16][0] == 57, key[16][1] == 72, key[16][2] == 91, key[16][3] == 96, key[16][4] == 125, key[16][5] == 105, key[16][6] == 94, key[16][7] == 235, key[16][8] == 138, key[16][9] == 39, key[16][10] == 145, key[16][11] == 130, key[16][12] == 126, key[16][13] == 147, key[16][14] == 254, key[16][15] == 179, key[16][16] == 181, key[16][17] == 183, key[16][18] == 216, key[16][19] == 211, sum[16] == 289929 not jump key[17][0] == 164, key[17][1] == 205, key[17][2] == 28, key[17][3] == 160, key[17][4] == 233, key[17][5] == 70, key[17][6] == 109, key[17][7] == 51, key[17][8] == 0, key[17][9] == 71, key[17][10] == 99, key[17][11] == 163, key[17][12] == 37, key[17][13] == 98, key[17][14] == 46, key[17][15] == 44, key[17][16] == 138, key[17][17] == 135, key[17][18] == 191, key[17][19] == 144, sum[17] == 221788 not jump key[18][0] == 13, key[18][1] == 240, key[18][2] == 143, key[18][3] == 53, key[18][4] == 75, key[18][5] == 23, key[18][6] == 26, key[18][7] == 224, key[18][8] == 31, key[18][9] == 199, key[18][10] == 182, key[18][11] == 220, key[18][12] == 130, key[18][13] == 61, key[18][14] == 170, key[18][15] == 130, key[18][16] == 253, key[18][17] == 240, key[18][18] == 182, key[18][19] == 9, sum[18] == 268459 not jump key[19][0] == 245, key[19][1] == 96, key[19][2] == 170, key[19][3] == 79, key[19][4] == 249, key[19][5] == 16, key[19][6] == 121, key[19][7] == 6, key[19][8] == 7, key[19][9] == 69, key[19][10] == 212, key[19][11] == 133, key[19][12] == 52, key[19][13] == 20, key[19][14] == 225, key[19][15] == 102, key[19][16] == 228, key[19][17] == 121, key[19][18] == 56, key[19][19] == 208, sum[19] == 247407
用z3解该方程组(建议使用z3++ python效率太低但是谁让我不会呢)
from z3 import * flag = [Int("flag_%s" % i) for i in range(20)] key = [[Int("key_%d_%d" % (i, j)) for j in range(20)] for i in range(20)] sum = [Int('sum_%d' % i) for i in range(20)] s = Solver() for i in range(20): s.add(sum[i] == 0) s.add(key[0][0] == 115, key[0][1] == 26, key[0][2] == 128, key[0][3] == 200, key[0][4] == 21, key[0][5] == 234, key[0][6] == 172, key[0][7] == 152, key[0][8] == 39, key[0][9] == 71, key[0][10] == 55, key[0][11] == 28, key[0][12] == 105, key[0][13] == 42, key[0][14] == 75, key[0][15] == 63, key[0][16] == 114, key[0][17] == 205, key[0][18] == 2, key[0][19] == 222, key[1][0] == 212, key[1][1] == 148, key[1][2] == 17, key[1][3] == 74, key[1][4] == 87, key[1][5] == 253, key[1][6] == 250, key[1][7] == 136, key[1][8] == 89, key[1][9] == 211, key[1][10] == 49, key[1][11] == 26, key[1][12] == 115, key[1][13] == 88, key[1][14] == 181, key[1][15] == 195, key[1][16] == 237, key[1][17] == 10, key[1][18] == 119, key[1][19] == 121, key[2][0] == 229, key[2][1] == 172, key[2][2] == 230, key[2][3] == 123, key[2][4] == 245, key[2][5] == 127, key[2][6] == 119, key[2][7] == 157, key[2][8] == 208, key[2][9] == 159, key[2][10] == 37, key[2][11] == 32, key[2][12] == 5, key[2][13] == 207, key[2][14] == 145, key[2][15] == 75, key[2][16] == 251, key[2][17] == 60, key[2][18] == 135, key[2][19] == 125, key[3][0] == 181, key[3][1] == 83, key[3][2] == 66, key[3][3] == 43, key[3][4] == 85, key[3][5] == 198, key[3][6] == 89, key[3][7] == 205, key[3][8] == 114, key[3][9] == 221, key[3][10] == 105, key[3][11] == 145, key[3][12] == 155, key[3][13] == 91, key[3][14] == 123, key[3][15] == 48, key[3][16] == 76, key[3][17] == 64, key[3][18] == 141, key[3][19] == 22, key[4][0] == 211, key[4][1] == 225, key[4][2] == 204, key[4][3] == 55, key[4][4] == 107, key[4][5] == 76, key[4][6] == 7, key[4][7] == 39, key[4][8] == 199, key[4][9] == 84, key[4][10] == 167, key[4][11] == 62, key[4][12] == 219, key[4][13] == 54, key[4][14] == 6, key[4][15] == 144, key[4][16] == 55, key[4][17] == 98, key[4][18] == 186, key[4][19] == 116, key[5][0] == 149, key[5][1] == 163, key[5][2] == 127, key[5][3] == 186, key[5][4] == 46, key[5][5] == 118, key[5][6] == 247, key[5][7] == 194, key[5][8] == 9, key[5][9] == 165, key[5][10] == 169, key[5][11] == 224, key[5][12] == 68, key[5][13] == 129, key[5][14] == 54, key[5][15] == 15, key[5][16] == 134, key[5][17] == 39, key[5][18] == 185, key[5][19] == 248, key[6][0] == 245, key[6][1] == 159, key[6][2] == 64, key[6][3] == 241, key[6][4] == 163, key[6][5] == 116, key[6][6] == 4, key[6][7] == 15, key[6][8] == 126, key[6][9] == 170, key[6][10] == 10, key[6][11] == 110, key[6][12] == 251, key[6][13] == 169, key[6][14] == 252, key[6][15] == 99, key[6][16] == 199, key[6][17] == 188, key[6][18] == 149, key[6][19] == 72, key[7][0] == 233, key[7][1] == 38, key[7][2] == 197, key[7][3] == 105, key[7][4] == 202, key[7][5] == 2, key[7][6] == 22, key[7][7] == 225, key[7][8] == 189, key[7][9] == 166, key[7][10] == 239, key[7][11] == 220, key[7][12] == 70, key[7][13] == 98, key[7][14] == 194, key[7][15] == 129, key[7][16] == 27, key[7][17] == 236, key[7][18] == 159, key[7][19] == 62, key[8][0] == 152, key[8][1] == 67, key[8][2] == 72, key[8][3] == 35, key[8][4] == 12, key[8][5] == 55, key[8][6] == 139, key[8][7] == 4, key[8][8] == 169, key[8][9] == 142, key[8][10] == 135, key[8][11] == 122, key[8][12] == 3, key[8][13] == 166, key[8][14] == 139, key[8][15] == 62, key[8][16] == 23, key[8][17] == 92, key[8][18] == 11, key[8][19] == 136, key[9][0] == 96, key[9][1] == 141, key[9][2] == 38, key[9][3] == 124, key[9][4] == 139, key[9][5] == 43, key[9][6] == 15, key[9][7] == 119, key[9][8] == 30, key[9][9] == 252, key[9][10] == 255, key[9][11] == 123, key[9][12] == 223, key[9][13] == 200, key[9][14] == 21, key[9][15] == 117, key[9][16] == 231, key[9][17] == 9, key[9][18] == 239, key[9][19] == 222, key[10][0] == 249, key[10][1] == 91, key[10][2] == 66, key[10][3] == 21, key[10][4] == 121, key[10][5] == 146, key[10][6] == 5, key[10][7] == 180, key[10][8] == 6, key[10][9] == 80, key[10][10] == 112, key[10][11] == 255, key[10][12] == 239, key[10][13] == 17, key[10][14] == 39, key[10][15] == 254, key[10][16] == 153, key[10][17] == 118, key[10][18] == 47, key[10][19] == 217, key[11][0] == 84, key[11][1] == 96, key[11][2] == 190, key[11][3] == 188, key[11][4] == 255, key[11][5] == 181, key[11][6] == 188, key[11][7] == 124, key[11][8] == 47, key[11][9] == 70, key[11][10] == 201, key[11][11] == 160, key[11][12] == 126, key[11][13] == 210, key[11][14] == 236, key[11][15] == 22, key[11][16] == 120, key[11][17] == 181, key[11][18] == 197, key[11][19] == 69, key[12][0] == 51, key[12][1] == 173, key[12][2] == 216, key[12][3] == 143, key[12][4] == 41, key[12][5] == 174, key[12][6] == 184, key[12][7] == 189, key[12][8] == 111, key[12][9] == 133, key[12][10] == 79, key[12][11] == 36, key[12][12] == 99, key[12][13] == 140, key[12][14] == 120, key[12][15] == 144, key[12][16] == 80, key[12][17] == 231, key[12][18] == 187, key[12][19] == 107, key[13][0] == 173, key[13][1] == 39, key[13][2] == 151, key[13][3] == 161, key[13][4] == 139, key[13][5] == 233, key[13][6] == 143, key[13][7] == 205, key[13][8] == 170, key[13][9] == 125, key[13][10] == 209, key[13][11] == 54, key[13][12] == 128, key[13][13] == 134, key[13][14] == 55, key[13][15] == 246, key[13][16] == 157, key[13][17] == 57, key[13][18] == 42, key[13][19] == 195, key[14][0] == 5, key[14][1] == 49, key[14][2] == 235, key[14][3] == 8, key[14][4] == 84, key[14][5] == 9, key[14][6] == 219, key[14][7] == 90, key[14][8] == 109, key[14][9] == 164, key[14][10] == 38, key[14][11] == 159, key[14][12] == 218, key[14][13] == 214, key[14][14] == 22, key[14][15] == 205, key[14][16] == 7, key[14][17] == 57, key[14][18] == 210, key[14][19] == 131, key[15][0] == 107, key[15][1] == 67, key[15][2] == 107, key[15][3] == 141, key[15][4] == 129, key[15][5] == 250, key[15][6] == 97, key[15][7] == 3, key[15][8] == 26, key[15][9] == 215, key[15][10] == 119, key[15][11] == 213, key[15][12] == 255, key[15][13] == 183, key[15][14] == 229, key[15][15] == 1, key[15][16] == 27, key[15][17] == 9, key[15][18] == 88, key[15][19] == 59, key[16][0] == 57, key[16][1] == 72, key[16][2] == 91, key[16][3] == 96, key[16][4] == 125, key[16][5] == 105, key[16][6] == 94, key[16][7] == 235, key[16][8] == 138, key[16][9] == 39, key[16][10] == 145, key[16][11] == 130, key[16][12] == 126, key[16][13] == 147, key[16][14] == 254, key[16][15] == 179, key[16][16] == 181, key[16][17] == 183, key[16][18] == 216, key[16][19] == 211, key[17][0] == 164, key[17][1] == 205, key[17][2] == 28, key[17][3] == 160, key[17][4] == 233, key[17][5] == 70, key[17][6] == 109, key[17][7] == 51, key[17][8] == 0, key[17][9] == 71, key[17][10] == 99, key[17][11] == 163, key[17][12] == 37, key[17][13] == 98, key[17][14] == 46, key[17][15] == 44, key[17][16] == 138, key[17][17] == 135, key[17][18] == 191, key[17][19] == 144, key[18][0] == 13, key[18][1] == 240, key[18][2] == 143, key[18][3] == 53, key[18][4] == 75, key[18][5] == 23, key[18][6] == 26, key[18][7] == 224, key[18][8] == 31, key[18][9] == 199, key[18][10] == 182, key[18][11] == 220, key[18][12] == 130, key[18][13] == 61, key[18][14] == 170, key[18][15] == 130, key[18][16] == 253, key[18][17] == 240, key[18][18] == 182, key[18][19] == 9, key[19][0] == 245, key[19][1] == 96, key[19][2] == 170, key[19][3] == 79, key[19][4] == 249, key[19][5] == 16, key[19][6] == 121, key[19][7] == 6, key[19][8] == 7, key[19][9] == 69, key[19][10] == 212, key[19][11] == 133, key[19][12] == 52, key[19][13] == 20, key[19][14] == 225, key[19][15] == 102, key[19][16] == 228, key[19][17] == 121, key[19][18] == 56, key[19][19] == 208) for i in range(20): for j in range(20): sum[i] += flag[j] * key[i][j] s.add(sum[0] == 217114, sum[1] == 270581, sum[2] == 291585, sum[3] == 234325, sum[4] == 240502, sum[5] == 277604, sum[6] == 286168, sum[7] == 290450, sum[8] == 179355, sum[9] == 272487, sum[10] == 249816, sum[11] == 305636, sum[12] == 276217, sum[13] == 294166, sum[14] == 237236, sum[15] == 242008, sum[16] == 289929, sum[17] == 221788, sum[18] == 268459, sum[19] == 247407) if s.check() == sat: m = s.model() print(''.join([chr(m[flag[i]].as_long()) for i in range(20)])) # have_fun_in_vm_hahaa
ezvm | vmre
与上一个vm不同的是引入了寄存器和flag位 采用函数表的方式存放op 还是先弄懂每个op的含义 然后模拟出加密过程:
# emulate the procees of vm ''' op_1_extract_v_from_reg_by_hb op_1_extract_v_from_reg_by_lb op_2_save_in_reg_by_hb op_3_nop ; pt += 1 op_4_add ; reg[hb] += reg[lb] op_5_minus ; reg[hb] -= reg[lb] op_6_mul ; reg[hb] *= reg[lb] op_7_div ; reg[hb] /= reg[lb] op_8_inc ; reg[hb] += 1 op_9_dec ; reg[hb] -= 1 op_10_xor ; reg[hb] ^= reg[lb] op_11_and ; reg[hb] &= reg[lb] op_12_pop_in ; pop reg[hb] in stack op_13 ; 组合op[9]接下来的4个数据(大端序)并入栈 op_14 ; esp += 4 op_15 ; reg[hb] = reg[lb] op_16 ; reg[hb] = input[k] op_17 ; input[k] = reg[hb] op_18 ; check reg[3]:reg[3] = 1 -> *op[9] -= *(op[9] + 1) op_19 ; set reg[4]:reg[4] = sign of (reg[hb] - reg[lb]) op_20 ; check reg[4]:reg[4] == -1 -> op[9] += 2 + *(op[9] + 1) else += 2 op_21 ; anti-op_20, reg[4] == 1 op_22 ; else reg[4] == 0 op_23 ; k++ op_24 ; k-- op_25 ; *(op[9] + i) ^= 0x66 for i in range(1, 16) ''' stack = [0] * 0x100 input_text = [ord(i) for i in input()] k = 0 reg = [0] * 5 esp = len(stack) - 1 opcode = [0x70, 0x00, 0x00, 0x00, 0x1E, 0x71, 0x30, 0x73, 0x00, 0x7A, 0x73, 0x10, 0x67, 0x01, 0x7B, 0x74, 0x00, 0x7A, 0x75, 0x0B, 0x70, 0x00, 0x00, 0x00, 0x1E, 0x71, 0x30, 0x7B, 0x75, 0x01, 0x70, 0x00, 0x00, 0x00, 0x1E, 0x71, 0x30, 0x73, 0x10, 0x7A, 0x73, 0x00, 0x6D, 0x01, 0x74, 0x00, 0x75, 0x09, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x0B, 0xDB, 0x0C, 0xE5, 0x08, 0xAD, 0xDE, 0xAF, 0xCD, 0x67, 0xBF, 0x1F, 0xBF, 0x1E, 0x68, 0xFE, 0x25, 0xFD, 0x6F, 0x08, 0x50, 0xCD, 0x15, 0xB0, 0x21, 0x8B, 0x3E, 0xFD, 0x73, 0xED, 0x90, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF] pointer_to_opcode = 0 while pointer_to_opcode < len(opcode): print("==================opcode: " + hex(opcode[pointer_to_opcode]), opcode[pointer_to_opcode] - 0x67 + 4, f"is excuted=======================opcode at {pointer_to_opcode}=====================") if opcode[pointer_to_opcode] == 0x66: print("failed") break if opcode[pointer_to_opcode] == 0x67: print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] += reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]") reg[opcode[pointer_to_opcode + 1] >> 4] += reg[opcode[pointer_to_opcode + 1] & 0x0F] pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x68: print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] -= reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]") reg[opcode[pointer_to_opcode + 1] >> 4] -= reg[opcode[pointer_to_opcode + 1] & 0x0F] pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x69: print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] *= reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]") reg[opcode[pointer_to_opcode + 1] >> 4] *= reg[opcode[pointer_to_opcode + 1] & 0x0F] pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x6A: print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] /= reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]") reg[opcode[pointer_to_opcode + 1] >> 4] /= reg[opcode[pointer_to_opcode + 1] & 0x0F] pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x6B: print(reg[opcode[pointer_to_opcode + 1] >> 4], "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] += 1", "\n") reg[opcode[pointer_to_opcode + 1] >> 4] += 1 pointer_to_opcode += 1 continue if opcode[pointer_to_opcode] == 0x6C: print(reg[opcode[pointer_to_opcode + 1] >> 4], "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] -= 1", "\n") reg[opcode[pointer_to_opcode + 1] >> 4] -= 1 pointer_to_opcode += 1 continue if opcode[pointer_to_opcode] == 0x6D: print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] ^= reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]") reg[opcode[pointer_to_opcode + 1] >> 4] ^= reg[opcode[pointer_to_opcode + 1] & 0x0F] pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x6E: print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] &= reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]") reg[opcode[pointer_to_opcode + 1] >> 4] &= reg[opcode[pointer_to_opcode + 1] & 0x0F] pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x6F: print(reg[opcode[pointer_to_opcode + 1] >> 4], "\n", "pop reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] in stack") esp -= 1 stack[esp] = reg[opcode[pointer_to_opcode + 1] >> 4] pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x70: data = opcode[pointer_to_opcode + 1] << 24 | opcode[pointer_to_opcode + 2] << 16 | opcode[pointer_to_opcode + 3] << 8 | opcode[pointer_to_opcode + 4] print("pop " + hex(data) + " in stack") esp -= 1 stack[esp] = data pointer_to_opcode += 5 continue if opcode[pointer_to_opcode] == 0x71: reg[opcode[pointer_to_opcode + 1] >> 4] = stack[esp] print(f"pop {stack[esp]} out to reg[{opcode[pointer_to_opcode + 1] >> 4}] and esp += 1") esp += 1 pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x72: print(reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F], "\n", "reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] = reg[" + str(opcode[pointer_to_opcode + 1] & 0xf) + "]") reg[opcode[pointer_to_opcode + 1] >> 4] = reg[opcode[pointer_to_opcode + 1] & 0x0F] pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x73: print("reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "] = input[" + str(k) + "]") reg[opcode[pointer_to_opcode + 1] >> 4] = input_text[k] pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x74: print("input[" + str(k) + "] = reg[" + str(opcode[pointer_to_opcode + 1] >> 4) + "]" ) input_text[k] = reg[opcode[pointer_to_opcode + 1] >> 4] pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x75: if reg[3]: print("jump to", hex(pointer_to_opcode - opcode[pointer_to_opcode + 1])) print(f"reg[3] = {reg[3]}") reg[3] -= 1 pointer_to_opcode -= opcode[pointer_to_opcode + 1] else: print("not jump") pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x76: if reg[opcode[pointer_to_opcode + 1] >> 4] == reg[opcode[pointer_to_opcode + 1] & 0x0F]: reg[4] = 0 pointer_to_opcode += 2 continue reg[4] = 1 if reg[opcode[pointer_to_opcode + 1] >> 4] > reg[opcode[pointer_to_opcode + 1] & 0x0F] else -1 print("set reg[4] to", reg[4], "cause", reg[opcode[pointer_to_opcode + 1] >> 4], reg[opcode[pointer_to_opcode + 1] & 0x0F]) pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x77: if reg[4] == 0: print("jump to", hex(pointer_to_opcode + opcode[pointer_to_opcode + 1])) pointer_to_opcode += opcode[pointer_to_opcode + 1] else: print("not jump cause reg[4] = ", reg[4]) pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x78: if reg[4] == 1: print("jump to", hex(pointer_to_opcode + opcode[pointer_to_opcode + 1])) pointer_to_opcode += opcode[pointer_to_opcode + 1] else: print("not jump cause reg[4] = ", reg[4]) pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x79: if reg[4] == -1: print("jump to", hex(pointer_to_opcode + opcode[pointer_to_opcode + 1])) pointer_to_opcode += opcode[pointer_to_opcode + 1] else: print("not jump cause reg[4] = ", reg[4]) pointer_to_opcode += 2 continue if opcode[pointer_to_opcode] == 0x7A: print("k++") k += 1 pointer_to_opcode += 1 continue if opcode[pointer_to_opcode] == 0x7B: print("k--") k -= 1 pointer_to_opcode += 1 continue if opcode[pointer_to_opcode] == 0x7C: for i in range(1, 16): print(opcode[pointer_to_opcode + 1], "\n", "opcode[" + str(pointer_to_opcode + i) + "] ^= 0x66") stack[esp + i] ^= 0x66 pointer_to_opcode += 16 continue pointer_to_opcode += 1
发现加密过程就是flag的每一位+=下一位(除最后一位) 然后再逆序每一位^=上一位(除第一位) 据此写出exp:
enc = [0xC7, 0x0B, 0xDB, 0x0C, 0xE5, 0x08, 0xAD, 0xDE, 0xAF, 0xCD, 0x67, 0xBF, 0x1F, 0xBF, 0x1E, 0x68, 0xFE, 0x25, 0xFD, 0x6F, 0x08, 0x50, 0xCD, 0x15, 0xB0, 0x21, 0x8B, 0x3E, 0xFD, 0x73, 0xED, 0x90] flag = "" for i in range(len(enc) - 1, 0, -1): enc[i] ^= enc[i - 1] for i in range(len(enc) - 1, 0, -1): enc[i - 1] -= enc[i] print(enc) for i in range(len(enc)): flag += chr(enc[i]) print(flag) # begin{r3@11y_A_B4by_34$y_FK_Vm!}