Hgame 2023
[HGAME 2023 week1]test your IDA
用ida開啟即可
[HGAME 2023 week1]encode
查殼
32位windows
加密函式
將輸入的位元組轉高位和低位進行加密,後與byte_403000進行比較
解密指令碼:
這裡採取了爆破
enc = [8, 6, 7, 6, 1, 6, 13, 6, 5, 6, 11, 7, 5, 6, 14, 6, 3, 6, 15, 6, 4, 6, 5, 6, 15, 5, 9, 6, 3, 7, 15, 5, 5, 6, 1, 6, 3, 7, 9, 7, 15, 5, 6, 6, 15, 6, 2, 7, 15, 5, 1, 6, 15, 5, 2, 7, 5, 6, 6, 7, 5, 6, 2, 7, 3, 7, 5, 6, 15, 5, 5, 6, 14, 6, 7, 6, 9, 6, 14, 6, 5, 6, 5, 6, 2, 7, 13, 7]
flag = ''
for j in range(0, len(enc), 2):
for i in range(32, 126):
if i & 0xF == enc[j] and (i >> 4) & 0xF == enc[j+1]:
flag += chr(i)
print(flag)
[HGAME 2023 week2]before_main
查殼:
64位linux無殼
找到主加密程式
大概是個base64加密
點開sub_12EB
直接點開裡面的table表檢視,按a換成字串
可以發現是替換了table表
但拿去解密是錯的
那應該就有可能是base64加密本身邏輯不同,或者有別的table表
觀察加密函式,沒有問題,那應該就是有別的table表了
交叉引用a0cxwsoemvjq4zd
可以看到確實有別的引用了這個table表
跟進
便可以看到別的table表,拿去解密即可
從網上抄的對映指令碼:
import base64 # 匯入base64模組用於解密
s1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' # 標準表
s2 = 'qaCpwYM2tO/RP0XeSZv8kLd6nfA7UHJ1No4gF5zr3VsBQbl9juhEGymc+WTxIiDK' # base64換表
en_text = 'AMHo7dLxUEabf6Z3PdWr6cOy75i4fdfeUzL17kaV7rG=' # 密文
map_text = '' # 用於存放密文透過換表對映回標準表的字元
for i in en_text:
if (i != '='): # 注意密文中存在等號的情況下,不需要替換!
idx = s2.index(i) # 獲取每個密文的字元在換表中的索引
map_text += s1[idx] # 取出標準表中的該索引的字元,就是正常base64加密的密文
else:
map_text += i
print(map_text) # 可以先看看標準表base64加密的密文
print(base64.b64decode(map_text)) # 直接使用提供的base64解密函式,獲得明文,就是flag
疑問
為什麼會是呼叫這個table表,可以看到程式執行的時候同步執行了init函式,我們跟進init函式即可找到剛剛的table表
[HGAME 2023 week1]easyasm
開啟附件是一個txt文字,裡面儲存了一個用匯編程式碼寫的加密程式
可以看到這裡有個異或和加密程式
其實可以直接猜是異或0x33
enc = [0x5b,0x54,0x52,0x5e,0x56,0x48,0x44,0x56,0x5f,0x50,0x3,0x5e,0x56,0x6c,0x47,0x3,0x6c,0x41,0x56,0x6c,0x44,0x5c,0x41,0x2,0x57,0x12,0x4e]
flag = ''
for i in enc:
flag += chr(i ^ 0x33)
print(flag)
得到flag
但還是得學著看彙編的hh
我自己的理解:
; void __cdecl enc(char *p)
.text:00401160 _enc proc near ; CODE XREF: _main+1B↑p //定義函式enc
.text:00401160
.text:00401160 i = dword ptr -4 //定義變數
.text:00401160 Str = dword ptr 8
.text:00401160
.text:00401160 push ebp
.text:00401161 mov ebp, esp //將基址指標ebp
.text:00401163 push ecx
.text:00401164 mov [ebp+i], 0
.text:0040116B jmp short loc_401176 //跳轉到loc_401176 開始迴圈
.text:0040116D ; ---------------------------------------------------------------------------
.text:0040116D
.text:0040116D loc_40116D: ; CODE XREF: _enc+3B↓j
.text:0040116D mov eax, [ebp+i] //將i載入到eax中
.text:00401170 add eax, 1 //將i值加1
.text:00401173 mov [ebp+i], eax //更新i的值
.text:00401176
.text:00401176 loc_401176: ; CODE XREF: _enc+B↑j
.text:00401176 mov ecx, [ebp+Str] //將str移動給ecx
.text:00401179 push ecx ; Str //將str壓棧
.text:0040117A call _strlen //用strlen獲取剛剛壓棧的str長度
.text:0040117F add esp, 4
.text:00401182 cmp [ebp+i], eax //比較i 與 eax大小
.text:00401185 jge short loc_40119D //如果i大於eax則跳轉loc_40119D
.text:00401187 mov edx, [ebp+Str] //將str地址賦值edx
.text:0040118A add edx, [ebp+i] //將str的地址+i的地址,即可實現對str陣列元素的獲取
.text:0040118D movsx eax, byte ptr [edx] //將edx地址中的元素轉byte賦值到eax暫存器
.text:00401190 xor eax, 33h //將eax與0x33異或,將異或結果儲存到了eax暫存器中的低地址al中,他只是對eax中的記憶體進行操作
.text:00401193 mov ecx, [ebp+Str] //將異或後的值賦值給ecx
.text:00401196 add ecx, [ebp+i] //再次載入str的第i個數
.text:00401199 mov [ecx], al //將加密後的結果移動到ecx中
.text:0040119B jmp short loc_40116D //跳轉到loc_40116D函式
.text:0040119D ; ---------------------------------------------------------------------------
.text:0040119D
.text:0040119D loc_40119D: ; CODE XREF: _enc+25↑j
.text:0040119D mov esp, ebp //回覆棧指標
.text:0040119F pop ebp //恢復基址指標
.text:004011A0 retn //結束函式
.text:004011A0 _enc endp
Input: your flag
Encrypted result: 0x5b,0x54,0x52,0x5e,0x56,0x48,0x44,0x56,0x5f,0x50,0x3,0x5e,0x56,0x6c,0x47,0x3,0x6c,0x41,0x56,0x6c,0x44,0x5c,0x41,0x2,0x57,0x12,0x4e
[HGAME 2023 week1]easyenc
die查殼
64位win
定位主程式
對v7陣列以byte型別進行操作
編寫指令碼
#include<stdio.h>
void main() {
int v8[10], v3, v5;
v8[0] = 167640836;
v8[1] = 11596545;
v8[2] = -1376779008;
v8[3] = 85394951;
v8[4] = 402462699;
v8[5] = 32375274;
v8[6] = -100290070;
v8[7] = -1407778552;
v8[8] = -34995732;
v8[9] = 101123568;
for (int i = 0; i < 41; i++)
{
v5 = (*((char*)v8 + i) + 86) ^ 0x32;
printf("%c", v5);
}
}
[HGAME 2023 week1]a_cup_of_tea
查殼
64win無殼
main函式
可以看到是接受引數Buf1和v10來加密然後與buf2進行比較
沒看到哪裡是v10的輸入,但v10和buf1的地址相近,所以v10應該也是buf1的輸入
tea加密
魔改delta的tea加密,進行四輪
返回看函式接收,接受了一個m128i_i32地址
smmword表示一個十六位元組字串
小端序儲存,因此可以推測這就是tea加密的key,當然也可以用動調來看tea加密中變數的賦值
編寫指令碼
#include <iostream>
using namespace std;
int main()
{
unsigned int enc[8] = { 778273437,-1051836401, -1690714183,1512016660,1636330974,1701168847,-1626976412,0x236A43F6 };
unsigned int key[4] = { 0x12345678, 0x23456789, 0x34567890, 0x45678901 };
int i, j;
for (i = 0;i < 8;i += 2) {
unsigned int delta = 0x543210DD;
int sum = -0x543210DD * 32;
for (j = 0; j < 32; j++) {
enc[i + 1] -= ((enc[i] << 4) + key[2]) ^ (enc[i] + sum) ^ ((enc[i] >> 5) + key[3]);
enc[i] -= ((enc[i + 1] << 4) + key[0]) ^ (enc[i + 1] + sum) ^ ((enc[i + 1] >> 5) + key[1]);
sum += delta;
}
}
printf("%s", enc);
return 0;
}
用python的ctypes庫
from ctypes import *
from binascii import *
from Crypto.Util import *
key = [0x12345678, 0x23456789, 0x34567890, 0x45678901]
enc = [0x2E63829D, 0xC14E400F, 0x9B39BFB9, 0x5A1F8B14, 0x61886DDE, 0x6565C6CF, 0x9F064F64, 0x236A43F6]
for i in range(0, len(enc), 2):
v0 = c_uint32(enc[i])
v1 = c_uint32(enc[i+1])
delta = 0x543210DD
sum = c_uint32(-delta * 32)
r = 32
for j in range(r):
v1.value -= (sum.value + v0.value) ^ (key[2] + 16 * v0.value) ^ (key[3] + (v0.value >> 5))
v0.value -= (sum.value + v1.value) ^ (key[0] + 16 * v1.value) ^ (key[1] + (v1.value >> 5))
sum.value += delta
enc[i] = v0.value
enc[i+1] = v1.value
print(a2b_hex(hex(enc[i])[2:].encode()).decode()[::-1],end='')
print(a2b_hex(hex(enc[i+1])[2:].encode()).decode()[::-1], end='')
# print(number.long_to_bytes(enc[i]).decode()[::-1],end="")
# print(number.long_to_bytes(enc[i+1]).decode()[::-1],end="")
#也可以用Crypto.Util庫的long_to_bytes列印
[HGAME 2023 week2]stream
python編譯的程式,使用pyinstxtractor-master來拆包
stream.pyc反編譯
import base64
def gen(key):
s = list(range(256))
j = 0
for i in range(256):
j = (j + s[i] + ord(key[i % len(key)])) % 256
tmp = s[i]
s[i] = s[j]
s[j] = tmp
i = j = 0
data = []
for _ in range(50):
i = (i + 1) % 256
j = (j + s[i]) % 256
tmp = s[i]
s[i] = s[j]
s[j] = tmp
data.append(s[(s[i] + s[j]) % 256])
return data
def encrypt(text, key):
result = ''
for c, k in zip(text, gen(key)):
result += chr(ord(c) ^ k)
result = base64.b64encode(result.encode()).decode()
return result
text = input('Flag: ')
key = 'As_we_do_as_you_know'
enc = encrypt(text, key)
if enc == 'wr3ClVcSw7nCmMOcHcKgacOtMkvDjxZ6asKWw4nChMK8IsK7KMOOasOrdgbDlx3DqcKqwr0hw701Ly57w63CtcOl':
print('yes!')
return None
None('try again...')
很簡單的python程式寫的異或加密
首先在加密函式中把k列印出來
再編寫指令碼
解密指令碼:
from base64 import *
key = [213, 242, 54, 127, 156, 227, 172, 100, 212, 1, 130, 92, 20, 189, 115, 12, 15, 228, 186, 225, 227, 75, 200, 119, 171, 11, 152, 15, 89, 160, 116, 157, 194, 226, 72, 147, 65, 74, 92, 21, 136, 193, 152, 94, 17, 178, 205, 195, 87, 145]
enc = 'wr3ClVcSw7nCmMOcHcKgacOtMkvDjxZ6asKWw4nChMK8IsK7KMOOasOrdgbDlx3DqcKqwr0hw701Ly57w63CtcOl'
tmp = b64decode(enc.encode()).decode()
flag = ''
for i in range(len(tmp)):
flag += chr(ord(tmp[i]) ^ key[i])
print(flag)
[HGAME 2023 week2]math
查殼:
64位linux無殼
分析
是一個簡單的矩陣相乘方程
from z3 import *
v12 = [63998, 33111, 67762, 54789, 61979, 69619, 37190, 70162, 53110, 68678, 63339, 30687, 66494, 50936, 60810, 48784, 30188, 60104, 44599, 52265, 43048, 23660, 43850, 33646, 44270]
v10 = [126, 225, 62, 40, 216, 253, 20, 124, 232, 122, 62, 23, 100, 161, 36, 118, 21, 184, 26, 142, 59, 31, 186, 82, 79]
x = [Int(f"x{i}") for i in range(25)]
s = Solver()
for i in range(5):
for j in range(5):
tmp = 0
for k in range(5):
tmp += x[5 * i + k] * v10[5 * k + j]
s.add(v12[5 * i + j] == tmp)
if s.check() == sat:
result = s.model()
print(result)
[HGAME 2023 week3]kunmusic
用dnspy開啟dll檔案
定位關鍵函式
這裡看入口點
在資源處儲存檔案
轉換文件指令碼
with open(r'D:\CTF\Reverse\Hgame\Hgame2023\[HGAME 2023 week3]kunmusic\kmusic\data', 'rb') as file:
str = file.read()
result = [0] * len(str)
for i in range(len(str)):
result[i] = (str[i] ^ 104)
output = bytes(result)
with open(r'D:\CTF\Reverse\Hgame\Hgame2023\[HGAME 2023 week3]kunmusic\kmusic\output.txt', 'wb') as file:
file.write(output)
丟入dnspy反編譯
找到關鍵加密函式
z3求解
from z3 import *
s = Solver()
num = [BitVec(f'num{i}',8) for i in range(13)]
array = [132, 47, 180, 7, 216, 45, 68, 6, 39, 246, 124, 2, 243, 137, 58, 172, 53, 200, 99, 91, 83, 13, 171, 80, 108, 235, 179, 58, 176, 28, 216, 36, 11, 80, 39, 162, 97, 58, 236, 130, 123, 176, 24, 212, 56, 89, 72]
s.add(num[0] + 52296 + num[1] - 26211 + num[2] - 11754 + (num[3] ^ 0xA114) + num[4] * 63747 + num[5] - 52714 + num[6] - 10512 + num[7] * 12972 + num[8] + 45505 + num[9] - 21713 + num[10] - 59122 + num[11] - 12840 + (num[12] ^ 0x525F) == 12702282 )
s.add( num[0] - 25228 + (num[1] ^ 0x50DB) + (num[2] ^ 0x1FDE) + num[3] - 65307 + num[4] * 30701 + num[5] * 47555 + num[6] - 2557 + (num[7] ^ 0xBF9F) + num[8] - 7992 + (num[9] ^ 0xE079) + (num[10] ^ 0xE052) + num[11] + 13299 + num[12] - 50966 == 9946829 )
s.add( num[0] - 64801 + num[1] - 60698 + num[2] - 40853 + num[3] - 54907 + num[4] + 29882 + (num[5] ^ 0x3506) + (num[6] ^ 0x533E) + num[7] + 47366 + num[8] + 41784 + (num[9] ^ 0xD1BA) + num[10] * 58436 + num[11] * 15590 + num[12] + 58225 == 2372055 )
s.add( num[0] + 61538 + num[1] - 17121 + num[2] - 58124 + num[3] + 8186 + num[4] + 21253 + num[5] - 38524 + num[6] - 48323 + num[7] - 20556 + num[8] * 56056 + num[9] + 18568 + num[10] + 12995 + (num[11] ^ 0x995C) + num[12] + 25329 == 6732474 )
s.add( num[0] - 42567 + num[1] - 17743 + num[2] * 47827 + num[3] - 10246 + (num[4] ^ 0x3F9C) + num[5] + 39390 + num[6] * 11803 + num[7] * 60332 + (num[8] ^ 0x483B) + (num[9] ^ 0x12BB) + num[10] - 25636 + num[11] - 16780 + num[12] - 62345 == 14020739 )
s.add( num[0] - 10968 + num[1] - 31780 + (num[2] ^ 0x7C71) + num[3] - 61983 + num[4] * 31048 + num[5] * 20189 + num[6] + 12337 + num[7] * 25945 + (num[8] ^ 0x1B98) + num[9] - 25369 + num[10] - 54893 + num[11] * 59949 + (num[12] ^ 0x3099) == 14434062 )
s.add( num[0] + 16689 + num[1] - 10279 + num[2] - 32918 + num[3] - 57155 + num[4] * 26571 + num[5] * 15086 + (num[6] ^ 0x59CA) + (num[7] ^ 0x5B35) + (num[8] ^ 0x3FFD) + (num[9] ^ 0x5A85) + num[10] - 40224 + num[11] + 31751 + num[12] * 8421 == 7433598 )
s.add( num[0] + 28740 + num[1] - 64696 + num[2] + 60470 + num[3] - 14752 + (num[4] ^ 0x507) + (num[5] ^ 0x89C8) + num[6] + 49467 + num[7] - 33788 + num[8] + 20606 + (num[9] ^ 0xAF4A) + num[10] * 19764 + num[11] + 48342 + num[12] * 56511 == 7989404 )
s.add( (num[0] ^ 0x7132) + num[1] + 23120 + num[2] + 22802 + num[3] * 31533 + (num[4] ^ 0x9977) + num[5] - 48576 + (num[6] ^ 0x6F7E) + num[7] - 43265 + num[8] + 22365 + num[9] + 61108 + num[10] * 2823 + num[11] - 30343 + num[12] + 14780 == 3504803 )
s.add( num[0] * 22466 + (num[1] ^ 0xDABF) + num[2] - 53658 + (num[3] ^ 0xB838) + (num[4] ^ 0x30DF) + num[5] * 59807 + num[6] + 46242 + num[7] + 3052 + (num[8] ^ 0x62BF) + num[9] + 30202 + num[10] * 22698 + num[11] + 33480 + (num[12] ^ 0x4175) == 11003580 )
s.add( num[0] * 57492 + (num[1] ^ 0x346D) + num[2] - 13941 + (num[3] ^ 0xBBDC) + num[4] * 38310 + num[5] + 9884 + num[6] - 45500 + num[7] - 19233 + num[8] + 58274 + num[9] + 36175 + (num[10] ^ 0x4888) + num[11] * 49694 + (num[12] ^ 0x2501) == 25546210 )
s.add( num[0] - 23355 + num[1] * 50164 + (num[2] ^ 0x873A) + num[3] + 52703 + num[4] + 36245 + num[5] * 46648 + (num[6] ^ 0x12FA) + (num[7] ^ 0xA376) + num[8] * 27122 + (num[9] ^ 0xA44A) + num[10] * 15676 + num[11] - 31863 + num[12] + 62510 == 11333836 )
s.add( num[0] * 30523 + (num[1] ^ 0x1F36) + num[2] + 39058 + num[3] * 57549 + (num[4] ^ 0xD0C0) + num[5] * 4275 + num[6] - 48863 + (num[7] ^ 0xD88C) + (num[8] ^ 0xA40) + (num[9] ^ 0x3554) + num[10] + 62231 + num[11] + 19456 + num[12] - 13195 == 13863722)
s.add(num[0]==ord('h')^array[0])
s.add(num[1]==ord('g')^array[1])
s.add(num[2]==ord('a')^array[2])
s.add(num[3]==ord('m')^array[3])
s.add(num[4]==ord('e')^array[4])
s.add(num[5]==ord('{')^array[5]) #z3多解,猜測求解
if s.check() == sat:
result = s.model()
num_values = [result[num[i]].as_long() for i in range(13)]
flag = ''
for i in range(len(array)):
flag += chr((array[i] ^ num_values[i % len(num_values)] ) & 0x7f )
print(flag)
[HGAME 2023 week2]VidarCamera
找到主加密程式
長度40的位元組
uIntArr是密文
檢視 m8encrypthkIa6DI函式
我改了一下變數名稱(有一說一java太醜了)
可以看到這裡有個很明顯的xtea加密
修改了delta,round,加密過程
(func1和func2點進去檢視是什麼意思,其實就是簡單的索引)
解密函式:
from ctypes import *
from Crypto.Util import *
enc = [0x260202FA, 0x1B451064, 0x867B61F1, 0x228033C5, 0xF15D82DC, 0x9D8430B1, 0x19F2B1E7, 0x2BBA859C, 0x2A08291D, 0xDC707918]
key = [2233, 4455, 6677, 8899]
for i in range(len(enc) - 2, -1, -1):
v0 = c_uint32(enc[i])
v1 = c_uint32(enc[i+1])
delta = 878077251
r = 33
sum = c_uint32(r * delta)
for j in range(r):
sum.value -= delta
v1.value -= (key[(sum.value >> 11) & 3] + sum.value) ^ (v0.value + ((v0.value >> 5) ^ (v0.value << 4)))
v0.value -= (key[sum.value & 3] + sum.value) ^ (v1.value + ((v1.value >> 5) ^ (v1.value << 4))) ^ sum.value
enc[i] = v0.value
enc[i+1] = v1.value
for i in range(10):
print(number.long_to_bytes(enc[i]).decode()[::-1], end='')
[HGAME 2023 week4]vm
點進主要加密函式
這裡就是虛擬機器的opcode,a1就是ip
匯入結構體(根據sub_140001000函式)
struct vm
{
_DWORD r[6];
_DWORD ip;
_DWORD esp;
_BYTE zf;
};
分析vm指令
mov
有賦值操作,即mov
push
點進stack,即可看到一堆未定義的空間
將暫存器的值賦值給這些空間,即可知道這是模擬壓棧操作
pop
與上面的類似,將stack中的值賦值給暫存器,模擬出棧操作(將上面的函式結合其實很容易看出來)
運算
進行了一系列運算,分別是add, sub, mul, xor, shl, shr
cmp
兩個if值的比較,如果比較成功則zf為0不成功則為1,為後面的jz和jnz服務的
jmp
跳轉到下一條opcode指令處,將opcode下一條指令賦值給ip
jz
JZ:jump if zero
如果if為假(即zf為0),則執行下一條指令
jnz
JNZ:jump if not zero
如果if為真(即zf不為0),則執行下一條指令
編寫指令碼
opcode = [ 0x00, 0x03, 0x02, 0x00, 0x03, 0x00, 0x02, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x03, 0x02, 0x32,
0x03, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
0x01, 0x00, 0x00, 0x03, 0x02, 0x64, 0x03, 0x00, 0x02, 0x03,
0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x01, 0x00, 0x00, 0x03,
0x00, 0x08, 0x00, 0x02, 0x02, 0x01, 0x03, 0x04, 0x01, 0x00,
0x03, 0x05, 0x02, 0x00, 0x03, 0x00, 0x01, 0x02, 0x00, 0x02,
0x00, 0x01, 0x01, 0x00, 0x00, 0x03, 0x00, 0x01, 0x03, 0x00,
0x03, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x01, 0x28,
0x04, 0x06, 0x5F, 0x05, 0x00, 0x00, 0x03, 0x03, 0x00, 0x02,
0x01, 0x00, 0x03, 0x02, 0x96, 0x03, 0x00, 0x02, 0x03, 0x00,
0x00, 0x00, 0x00, 0x04, 0x07, 0x88, 0x00, 0x03, 0x00, 0x01,
0x03, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03,
0x01, 0x28, 0x04, 0x07, 0x63, 0xFF, 0xFF]
i = 0
for j in range(10000):
if opcode[i] == 0xff:
break
match opcode[i]:
case 0: #mov
print(f'({i})', end=' ') #地址
match (opcode[i + 1]):
case 1:
print('mov flag[r[2]], r[1]')
case 2:
print(f'mov r[{opcode[i + 2]}], r[{opcode[i + 3]}]')
case 3:
print(f'mov r[{opcode[i + 2]}], {opcode[i + 3]}')
case _:
print('mov r[0], flag[r[2]] ')
i += 4
case 1: #push
print(f'({i})', end=' ')
match (opcode[i + 1]):
case 1:
print('push r[0]')
case 2:
print('push r[2]')
case 3:
print('case r[3]')
case _:
print('push r[0]')
i += 2
case 2: #pop
print(f'({i})', end=' ')
match (opcode[i + 1]):
case 1:
print('pop r[1]')
case 2:
print('pop r[2]')
case 3:
print('pop r[3]')
case _:
print('pop r[0]')
i += 2
case 3: #運算
print(f'({i})', end=' ')
match (opcode[i + 1]):
case 0:
print(f'add r{[opcode[i + 2]]} r{[opcode[i + 3]]}')
case 1:
print(f'sub r{[opcode[i + 2]]} r{[opcode[i + 3]]}')
case 2:
print(f'mul r{[opcode[i + 2]]} r{[opcode[i + 3]]}')
case 3:
print(f'xor r{[opcode[i + 2]]} r{[opcode[i + 3]]}')
case 4:
print(f'shl r{[opcode[i + 2]]} r{[opcode[i + 3]]}')
case 5:
print(f'shr r{[opcode[i + 2]]} r{[opcode[i + 3]]}')
i += 4
case 4: #cmp
print(f'({i})', end=' ')
print('cmp r[0] r[1]')
i += 1
case 5: #jmp
print(f'({i})', end=' ')
print(f'jmp {opcode[i + 1]}')
i += 2
case 6: #jz
print(f'({i})', end=' ')
print(f'jz {opcode[i + 1]}')
i += 2
case 7: #jnz
print(f'({i})', end=' ')
print(f'jnz {opcode[i + 1]}')
i += 2
列印出來的彙編指令(我給了一些註釋)
(0) mov r[2], 0
(4) add r[2] r[3] //r[3]就是i
(8) mov r[0], flag[r[2]] //這裡的flag[r[2]]就是輸入的input
(12) mov r[1], r[0]
(16) mov r[2], 50
(20) add r[2] r[3]
(24) mov r[0], flag[r[2]] //將flag記憶體處偏移50 + i的值存入r[0]
(28) add r[1] r[0] //將input 與 偏移50+i的值相加
(32) mov r[2], 100
(36) add r[2] r[3]
(40) mov r[0], flag[r[2]] //將flag記憶體處偏移100 + i的值存入r[0]
(44) xor r[1] r[0] //將input 與 偏移100+i的值異或,將值存入v[1]
(48) mov r[0], 8 //賦值8給r[0]
(52) mov r[2], r[1]
(56) shl r[1] r[0]
(60) shr r[2] r[0]
(64) add r[1] r[2] //將異或後的值左移八位右移八位相加存入r[1](也就是低八位和高八位換位)
(68) mov r[0], r[1] //將運算結果儲存在r[0]中
(72) push r[0] //將運算結果壓入棧中
(74) mov r[0], 1
(78) add r[3] r[0]
(82) mov r[0], r[3]
(86) mov r[1], 40
(90) cmp r[0] r[1] //判斷迴圈結束
(91) jz 95
(93) jmp 0
(95) mov r[3], 0
(99) pop r[1] //將結果出棧儲存到r[1]中,所以最後一個結果先與第一個比較
(101) mov r[2], 150
(105) add r[2] r[3]
(109) mov r[0], flag[r[2]]
(113) cmp r[0] r[1] //將運算結果與偏移150位的資料比較
(114) jnz 136
(116) mov r[0], 1
(120) add r[3] r[0]
(124) mov r[0], r[3]
(128) mov r[1], 40
(132) cmp r[0] r[1] //繼續迴圈
(133) jnz 99
將輸入與input記憶體偏移50處的值相加,後與偏移100的值異或,最後與偏移150處的值逆序(出棧壓棧操作導致的)比較
編寫解密指令碼
enc = [18432, 61696, 16384, 8448, 13569, 25600, 30721, 63744, 6145, 20992, 9472, 23809, 18176, 64768, 26881, 23552, 44801, 45568, 60417, 20993
, 20225, 6657, 20480, 34049, 52480, 8960, 63488, 3072, 52992, 15617, 17665, 33280, 53761, 10497, 54529, 1537, 41473, 56832, 42497, 51713]
enc = enc[::-1]
key2 =[155, 168, 2, 188, 172, 156, 206, 250, 2, 185, 255, 58, 116, 72, 25, 105, 232, 3, 203, 201, 255, 252, 128, 214, 141, 215, 114, 0, 167, 29, 61, 153, 136
, 153, 191, 232, 150, 46, 93, 87]
key1 = [201, 169, 189, 139, 23, 194, 110, 248, 245, 110, 99, 99, 213, 70, 93, 22, 152, 56, 48, 115, 56, 193, 94, 237, 176,
41, 90, 24, 64, 167, 253, 10, 30, 120, 139, 98, 219, 15, 143, 156]
flag = ''
for i in range(len(enc)):
tmp1 = (enc[i] & 0xFF << 8) + ((enc[i] >> 8) & 0xFF)
tmp2 = tmp1 ^ key1[i]
tmp3 = tmp2 - key2[i]
flag += chr(tmp3 & 0xff)
print(flag)
flag : hgame{y0ur_rever5e_sk1ll_i5_very_g0od!!}
高低位互換操作:
b = 18432
low_byte = b & 0xFF # 低八位 (masking with 0xFF)
high_byte = (b >> 8) & 0xFF # 高八位 (shift right and mask with 0xFF)
swapped_value = (low_byte << 8) + high_byte
[HGAME 2023 week3]cpp
全靠大佬wp成就TAT
進入醜的一b的main函式
甚至都沒翻到哪裡對input進行加密了
那就先動調
下斷點動調
既然都不知道input都有多長,那就先輸入一個比較長的數
一直f7步入
進入到一個不知道幹啥的函式
跳出去繼續f7
這次進入了一個疑似加密的函式,是一個異或函式
跳到異或部分
這裡就是把eax和ecx進行異或,eax應該就是加密值,但我不知道為什麼
使用ida指令碼列印ecx的值
from idaapi import *
print(hex(get_reg_val("ecx")),end = ',')
0x4037a04e,0xfdda0246,0x3c6efa21,0xcf9cd9af,0x673347b9,0xdec4ee0,0x1380c4d1,0x3ab2a932,0x25d50a7,0x834a3982,0xcb6ea25f,0xa26ba4ab,0xa1c42135,0xd1063eba,0x2397fefc,0x55c7d126,0xabababab
進入比較函式
還有兩位在彙編介面看
這就是一個比較函式
可以看到enc長度是40,那key應該也是40
編寫彙編指令碼
from struct import *
key = [0x4037a04e,0xfdda0246,0x3c6efa21,0xcf9cd9af,0x673347b9,0xdec4ee0,0x1380c4d1,0x3ab2a932,0x25d50a7,0x834a3982]
enc = [0x28, 0x50, 0xC1, 0x23, 0x98, 0xA1, 0x41, 0x36, 0x4C, 0x31, 0xCB, 0x52, 0x90, 0xF1, 0xAC, 0xCC, 0xF, 0x6C, 0x2A, 0x89, 0x7F, 0xDF, 0x11, 0x84, 0x7F, 0xE6, 0xA2, 0xE0, 0x59, 0xC7, 0xC5, 0x46, 0x5D, 0x29, 0x38, 0x93, 0xED, 0x15, 0x7A, 0xFF,]
key_LE = []
flag = []
for i in key:
key_LE.extend((pack('>I', i)))
for i in range(len(enc)):
print(chr(key_LE[i] ^ enc[i]), end='')
貌似是需要把enc進行小端序轉換的,我這邊直接把key大端序列印了,方便點
hgame{Cpp_1s_much_m0r3_dlff1cult_th4n_C}
只能說不懂的多的一b,哎哎,看wp也沒看懂