前言:第一次参加,只写了前两个,最后一个赛后复现。写的尽量详细一点,希望大家都能看懂
snake
运行贪吃蛇游戏
进行查壳
解包一下
在解包的文件中找到与文件名相同的.pyc文件\snake\snake.exe_extracted\snack.pyc
老本的pyinstxtractor.py可能生成的不是.pyc文件,需要用010补一下文件头
55 0D 0D 0A 00 00 00 00 00 00 00 00 00 00 00 00,再将末尾改为.pyc就可以使用工具了
snake.pyc包含了游戏逻辑与加密算法,简单筛选一下保留加密算法部分(游戏逻辑显示大于9999分就可以直接获得flag,so游戏佬除外)
#魔改RC4
import random
import key
def initialize(key):
key_length = len(key)
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % key_length]) % 256
S[i] = S[j]
S[j] = S[i]
return S
def generate_key_stream(S, length):
i = 0
j = 0
key_stream = []
for _ in range(length):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i] = S[j]
S[j] = S[i]
key_stream.append(S[(S[i] + S[j]) % 256])
return key_stream
def decrypt(data, key):
S = initialize(key)
key_stream = generate_key_stream(S, len(data))
decrypted_data = None((lambda .0 = None: [ i ^ data[i] ^ key_stream[i] for i in .0 ])(range(len(data))))
return decrypted_data
key_bytes = bytes((lambda .0: [ ord(char) for char in .0 ])(key.xor_key))
data = [101,97,39,125,218,172,205,3,235,195,72,125,89,130,103,213,120,227,193,67,174,71,162,248,244,12,238,92,160,203,185,155]
decrypted_data = decrypt(bytes(data), key_bytes)
在解包的PYZ-00.pyz_extracted中找一下key.pyc,有的pyinstxtractor.py得到的文件夹为空,可以换一个版本进行解决,反编译得到key
推荐几个反编译pyc的网站:
exp:
def rc4_decrypt(key, length):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
i = j = 0
text = []
for _ in range(length):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
text.append(S[(S[i] + S[j]) % 256])
return text
key = b'V3rY_v3Ry_Ez'
data = [101, 97, 39, 125, 218, 172, 205, 3, 235, 195, 72, 125, 89, 130, 103, 213, 120, 227, 193, 67, 174, 71, 162, 248, 244, 12, 238, 92, 160, 203, 185, 155]
text = rc4_decrypt(key, len(data))
flag = ''
for i in range(len(data)):
flag += chr(data[i] ^ text[i] ^ i)
print(flag)
得到flag{KMLTz3lT_MePUDa7A_P5LpzCBT}
HardSignin
无法运行程序,直接查壳——upx,直接使用工具脱不了,应该是被魔改了,010查看一下
使用另外一个查壳工具发现改成了vmp,修改回来(共三处UPX1,UPX2,UPX!)
使用UPX Unpacker或者指令upx -d HardSignin.exe都可以
使用ida32打开发现没有main函数
对_main进行交叉引用Upo.text:loc_401029mov dword ptr [ebp-4], offset _main,发现四个TLS回调函数,但是存在基础花指令修改一下
第一处:(右键->Patching->change byte->E2改为90->快捷键C转为汇编代码)
第二处:(右键->Patching->change byte->9A改为90->快捷键C转为汇编代码)
第二处:(右键->Patching->change byte->C2改为90->快捷键C转为汇编代码)
TlsCallback_0,TlsCallback_1,TlsCallback_2后按快捷键P转换为函数
TlsCallback_0函数存在一点问题,字节异或0x66
由于是可以运算,我们直接写exp,shift+F2打开编辑窗口,编写脚本
from ida_bytes import *
addr = 0x00401890
for i in range(170):
patch_byte(addr + i,get_wide_byte(addr + i)^0x66)
C+P转换得到主函数main:
分析encrypt函数:
其余密文的脚本(由于XTEA加密是四字节所以64//4):
from ida_bytes import *
from idaapi import *
addr = 0x00404000
enc = []
for i in range(64//4):
enc.append(get_dword(addr + i * 4))
print(enc)
#[3036486489, 3653154923, 3598177203, 408905200, 1396350368, 645614189, 1318861428, 3625534240, 3046501746, 1445070236, 2433841867, 213678751, 3463276874, 699118653, 845347425, 3058494644]
两个加密的key都是随机生成的,交叉索引找到TLS1和TLS2
srand(0x114514u)是mz_base64的随机种子
srand(0x1919810u)是mz_RC4和mz_XTEA的随机数种子
- 解密mz_XTEA:
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<string.h>
void XTEA_decrypt(uint32_t* enc, uint32_t* key);
int main() {
uint8_t RC4_key[16] = { 0 };
char XTEA_key[16] = { 0 };
uint32_t enc[] = { 3036486489, 3653154923, 3598177203, 408905200, 1396350368, 645614189, 1318861428, 3625534240, 3046501746, 1445070236, 2433841867, 213678751, 3463276874, 699118653, 845347425, 3058494644 };
srand(0x1919810u);
for (int i = 0; ; ++i){
if (i >= 16)
break;
RC4_key[i] = rand() % 255;
XTEA_key[i] = rand() % 255;
}
XTEA_decrypt(enc, (uint32_t*)XTEA_key);//指针强转
//uint8_t* temp = (uint8_t*)enc;
for (int i = 0; i < 16; i++) {
//printf("%d, ", temp[i]);
printf("%d, ", RC4_key[i]);
}
return 0;
}
void XTEA_decrypt(uint32_t* enc, uint32_t* XTEA_key) {
uint32_t v7, v6, v5;
for (int i = 0; i < 16; i += 2){
v7 = enc[i];
v6 = enc[i + 1];
v5 = 0x9E3779B9 * 0x64;
for (int j = 0; j < 0x64; ++j)
{
v6 -= (XTEA_key[(v5 >> 11) & 3] + v5) ^ (v7 + ((v7 >> 5) ^ (16 * v7)));
v5 -= 0x9E3779B9;
v7 -= (XTEA_key[v5 & 3] + v5) ^ (v6 + ((v6 >> 5) ^ (16 * v6)));
}
enc[i] = v7;
enc[i + 1] = v6;
}
}
得到:188, 237, 0, 123, 134, 244, 22, 147, 149, 249, 135, 220, 103, 168, 162, 127, 77, 226, 98, 159, 123, 52, 174, 233, 69, 3, 126, 53, 66, 208, 139, 112, 240, 251, 46, 199, 221, 233, 185, 115, 227, 204, 26, 117, 173, 220, 253, 20, 168, 200, 69, 22, 49, 110, 42, 8, 44, 15, 29, 159, 7, 186, 213, 239
- 解密mz_RC4
def rc4_decrypt(ciphertext, key):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
i = j = 0
plaintext = []
for byte in ciphertext:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
plaintext.append(byte ^ k)
return bytes(plaintext)
enc = [188, 237, 0, 123, 134, 244, 22, 147, 149, 249, 135, 220, 103, 168, 162, 127, 77, 226, 98, 159, 123, 52, 174, 233,
69, 3, 126, 53, 66, 208, 139, 112, 240, 251, 46, 199, 221, 233, 185, 115, 227, 204, 26, 117, 173, 220, 253, 20,
168, 200, 69, 22, 49, 110, 42, 8, 44, 15, 29, 159, 7, 186, 213, 239]
RC4_key = [118, 137, 51, 73, 25, 19, 195, 199, 173, 216, 228, 104, 252, 72, 4, 188]
decrypted_data = rc4_decrypt(enc, RC4_key)
print(decrypted_data)
#b'C+vFCnHRGPghbmyQMXvFMRNd7fNCG8jcU+jcbnjRJTj2GTCOGUvgtOS0CTge7fNs'
- 解密mz_base64
求变表
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void swap(char* a, char* b) {
char temp = *a;
*a = *b;
*b = temp;
}
int main() {
char base64table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int v6, v4;
srand(0x114514u);
for (int i = 0; i < 100; ++i) {
v6 = rand() % 64;
v4 = rand() % 64;
swap(&base64table[v6], &base64table[v4]);
}
printf("%s\n", base64table);
return 0;
}
//4yZRiNP8LoK/GSA5ElWkUjXtJCz7bMYcuFfpm6+hV0rxeHIdwv32QOTnqg1BDsa9
解密:
import base64
text1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
text2 = '4yZRiNP8LoK/GSA5ElWkUjXtJCz7bMYcuFfpm6+hV0rxeHIdwv32QOTnqg1BDsa9'
enc = 'C+vFCnHRGPghbmyQMXvFMRNd7fNCG8jcU+jcbnjRJTj2GTCOGUvgtOS0CTge7fNs'
decoded_bytes = base64.b64decode(enc.translate(str.maketrans(text2, text1)))
print(decoded_bytes.decode("utf-8"))
flag{C0ngr@tulat1on!Y0u_Re_suCces3fu1Ly_Signln!}
bedtea
运行代码,无壳直接用IDA64打开,一个C++程序
main函数还是比较复杂的
逻辑:flag->魔改TEA加密->二叉树倒叙->异或0x33->enc
难点在于密文和密钥都是隐藏的,需要进行动态调试,但是动调调试会出现不正确的密文,需要修改检测动态调试的值,在此之前看一下魔改的TEA是怎么样的吧!
本地动态调试就可以,在此下断点
发现RAX寄存器为1,修改一下
去sub_401E80()函数观察xmmword_408040(TEA_key)的变化,F9运行,两个地址来回断
记录一下:0x03050D08,0x15223759,0x90E9179262
密文地址:
写脚本提取一下(为了方便起见直接倒叙加异或):
from idaapi import *
import ida_bytes
enc = []
addr = 0x0000000000405080
for i in range(24):
enc.append(ida_bytes.get_word(addr + i * 2))
enc.reverse()
dec = [x ^ 0x33 for x in enc]
print(dec)
[211, 109, 186, 193, 54, 101, 42, 137, 120, 145, 245, 49, 250, 190, 194, 49, 144, 12, 68, 67, 212, 174, 66, 69]
exp:(本来想写个自动化脚本,但是时间成本太高了,一共加密三大轮回,替换都比解决bug快,难受)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main() {
uint8_t enc[] = { 211, 109, 186, 193, 54, 101, 42, 137 };
//{ 120, 145, 245, 49, 250, 190, 194, 49 }
//{ 144, 12, 68, 67, 212, 174, 66, 69}
uint32_t* denc = (uint32_t*)enc;
uint32_t v15 = denc[0];
uint32_t v13 = denc[1];
uint32_t v14 = 0x9E3449B8 * 22;
//key1[] = {0x03, 0x05, 0x0D, 0x08}
//key2[] = {0x15, 0x22, 0x37, 0x59}
//key3[] = {0x90, 0xE9, 0x179, 0x262};
for (int i = 0; i < 22; i++) {
v13 -= (v14 + v15) ^ (0x0D + (v15 >> 4)) ^ (0x08 + 32 * v15);
v15 -= (v14 + v13) ^ (0x05 + (v13 >> 4)) ^ (0x03 + 32 * v13);
v14 -= 0x9E3449B8;
}
denc[0] = v15;
denc[1] = v13;
printf("%s\n", enc);
return 0;
}
得到:
flag{y0ux戸1??DC援BE烫烫嚈`榾
_reallyl烫烫?騡待?
1ke_te@}烫烫獞胇X鷞
手动拼接:flag{y0u_reallyl1ke_te@}(flag{y0ux_reallyl1ke_te@}不对一下就知道了,在提交答案时还设置了坑)