Hgame2023 Reverse

news/2024/12/24 11:30:32/文章来源:https://www.cnblogs.com/murasame520/p/18548674

Hgame 2023

[HGAME 2023 week1]test your IDA

用ida打开即可

[HGAME 2023 week1]encode

查壳image-20241106135704303

32位windows

加密函数

image-20241106144724863

将输入的字节转高位和低位进行加密,后与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

查壳:

image-20241106145106892

64位linux无壳

找到主加密程序

image-20241106151208838

大概是个base64加密

点开sub_12EB

image-20241106151233417

直接点开里面的table表查看,按a换成字符串

image-20241106151251508

可以发现是替换了table表

但拿去解密是错的

那应该就有可能是base64加密本身逻辑不同,或者有别的table表

观察加密函数,没有问题,那应该就是有别的table表了

交叉引用a0cxwsoemvjq4zd

image-20241106151414391

可以看到确实有别的引用了这个table表

跟进

image-20241106152555619

便可以看到别的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表image-20241106152705919

[HGAME 2023 week1]easyasm

打开附件是一个txt文本,里面储存了一个用汇编代码写的加密程序

image-20241106153651967

可以看到这里有个异或和加密程序

其实可以直接猜是异或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查壳

image-20241106171829452

64位win

定位主程序

image-20241106183124094

对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

查壳

image-20241106183359746

64win无壳

main函数

image-20241106202555776

可以看到是接受参数Buf1和v10来加密然后与buf2进行比较

没看到哪里是v10的输入,但v10和buf1的地址相近,所以v10应该也是buf1的输入

tea加密

image-20241106203229555

魔改delta的tea加密,进行四轮

返回看函数接收,接受了一个m128i_i32地址

image-20241106203348716

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 = 0x543210DDsum = c_uint32(-delta * 32)r = 32for 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 += deltaenc[i] = v0.valueenc[i+1] = v1.valueprint(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来拆包

image-20241107220021032

stream.pyc反编译

import base64def gen(key):s = list(range(256))j = 0for i in range(256):j = (j + s[i] + ord(key[i % len(key)])) % 256tmp = s[i]s[i] = s[j]s[j] = tmpi = j = 0data = []for _ in range(50):i = (i + 1) % 256j = (j + s[i]) % 256tmp = s[i]s[i] = s[j]s[j] = tmpdata.append(s[(s[i] + s[j]) % 256])return datadef encrypt(text, key):result = ''for c, k in zip(text, gen(key)):result += chr(ord(c) ^ k)result = base64.b64encode(result.encode()).decode()return resulttext = input('Flag: ')
key = 'As_we_do_as_you_know'
enc = encrypt(text, key)
if enc == 'wr3ClVcSw7nCmMOcHcKgacOtMkvDjxZ6asKWw4nChMK8IsK7KMOOasOrdgbDlx3DqcKqwr0hw701Ly57w63CtcOl':print('yes!')return None
None('try again...')

很简单的python程序写的异或加密

image-20241107221851175

首先在加密函数中把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

查壳:

image-20241107222041409

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 = 0for 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文件

定位关键函数

这里看入口点

image-20241108211525781

image-20241108191928713

在资源处保存文件

image-20241108202017307

转换文档脚本

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反编译

image-20241109110631309

找到关键加密函数

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

找到主加密程序

image-20241109112054883

长度40的字节

uIntArr是密文

查看 m8encrypthkIa6DI函数

image-20241109160401129

我改了一下变量名称(有一说一java太丑了)

image-20241109160421623

可以看到这里有个很明显的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 = 878077251r = 33sum = c_uint32(r * delta)for j in range(r):sum.value -= deltav1.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.valueenc[i] = v0.valueenc[i+1] = v1.value
for i in range(10):print(number.long_to_bytes(enc[i]).decode()[::-1], end='')

[HGAME 2023 week4]vm

image-20241111133632240

点进主要加密函数image-20241111133640284

这里就是虚拟机的opcode,a1就是ip

导入结构体(根据sub_140001000函数)

image-20241111165158083

struct vm
{_DWORD r[6];_DWORD ip;_DWORD esp;_BYTE zf;
};

分析vm指令

image-20241112121848666

mov

image-20241112121900440

有赋值操作,即mov

push

image-20241112122024679

点进stack,即可看到一堆未定义的空间

将寄存器的值赋值给这些空间,即可知道这是模拟压栈操作

pop

image-20241112122138416

与上面的类似,将stack中的值赋值给寄存器,模拟出栈操作(将上面的函数结合其实很容易看出来)

运算

image-20241112122234485

进行了一系列运算,分别是add, sub, mul, xor, shl, shr

cmp

image-20241112122345377

两个if值的比较,如果比较成功则zf为0不成功则为1,为后面的jz和jnz服务的

jmp

image-20241112122913255

跳转到下一条opcode指令处,将opcode下一条指令赋值给ip

jz

image-20241112122651008

JZ:jump if zero

如果if为假(即zf为0),则执行下一条指令

jnz

image-20241112123144319

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:breakmatch opcode[i]:case 0:   #movprint(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 += 4case 1:     #pushprint(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 += 2case 2:   #popprint(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 += 2case 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 += 4case 4:   #cmpprint(f'({i})', end=' ')print('cmp r[0] r[1]')i += 1case 5:   #jmpprint(f'({i})', end=' ')print(f'jmp {opcode[i + 1]}')i += 2case 6:   #jzprint(f'({i})', end=' ')print(f'jz {opcode[i + 1]}')i += 2case 7:   #jnzprint(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函数

image-20241112210625740

甚至都没翻到哪里对input进行加密了

那就先动调

下断点动调

既然都不知道input都有多长,那就先输入一个比较长的数

image-20241112210911330

一直f7步入

image-20241112211201797

进入到一个不知道干啥的函数

跳出去继续f7

image-20241112211259976

这次进入了一个疑似加密的函数,是一个异或函数

跳到异或部分image-20241112212129159

这里就是把eax和ecx进行异或,eax应该就是加密值,但我不知道为什么

使用ida脚本打印ecx的值

from idaapi import *
print(hex(get_reg_val("ecx")),end = ',')

image-20241112213437133

0x4037a04e,0xfdda0246,0x3c6efa21,0xcf9cd9af,0x673347b9,0xdec4ee0,0x1380c4d1,0x3ab2a932,0x25d50a7,0x834a3982,0xcb6ea25f,0xa26ba4ab,0xa1c42135,0xd1063eba,0x2397fefc,0x55c7d126,0xabababab

进入比较函数

image-20241112213532565

image-20241112213553284

还有两位在汇编界面看

image-20241112213633737

这就是一个比较函数

可以看到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也没看懂

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/834249.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[笔记]Dijkstra算法正确性证明

最近做了一些题,感觉对算法更深刻的理解是比套板子更深层次的,在这个层次上解决问题,思路会更加清晰。比如P5687 [CSP-S2019 江西] 网格图(题解)这道题就是网格图的最小生成树,解法就建立在普通Kruskal的基础上,当时想了挺久也没想出来,看了题解才豁然开朗。所以各算法…

企业搭建帮助中心:提升服务效率与客户满意度的双重优势

在当今快节奏的商业环境中,企业面临着日益增长客户服务需求。搭建一个有效的帮助中心,不仅能够提升服务效率,还能增强客户满意度,这对于企业的长期发展至关重要。本文将探讨企业搭建帮助中心的优势,并提供实用的策略。 在构建企业帮助中心的过程中,HelpLook作为一个强大的…

软件管理,磁盘存储,文件系统以及网络协议

目录硬盘存储术语CHS 磁盘存储管理 LVM RAID硬盘阵列 软件包管理 搭建私有yum仓库 系统安装之后的常用初始化步骤 OSI七层模型 linux端口的简单介绍 TCP简单介绍 ip地址分类硬盘存储术语CHShead:磁头 磁头数=盘面数 track:磁道 磁道=柱面数 sector:扇区,512bytes cylinder:…

【Capture one 2023软件下载与安装教程】

1、安装包 「Capture One 23」: 链接:https://pan.quark.cn/s/9ff0306530d1 提取码:xXDC 「Capture one22」: 链接:https://pan.quark.cn/s/34b723a4d6e1 提取码:gpM3 「Capture One 21」: 链接:https://pan.quark.cn/s/d65ea77ba33a 提取码:8A5D 2、安装教程(建议关闭杀…

[题解]P5687 [CSP-S2019 江西] 网格图

P5687 [CSP-S2019 江西] 网格图 简单来说题目就是给定一个\(n\times m\)的网格图,同行边权相同,同列边权相同,求该网格图的最小生成树。 根据Kruskal算法的贪心思想,我们要优先选择权值尽可能小的行,并将这条边应用于尽可能多的列。列方向同理。 为了保证最终生成树的连通…

鸿蒙NEXT自定义组件:太极Loading

【引言】(完整代码在最后面) 本文将介绍如何在鸿蒙NEXT中创建一个自定义的“太极Loading”组件,为你的应用增添独特的视觉效果。 【环境准备】 电脑系统:windows 10 开发工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806 工程版本:API 12 真机:mate60 pro 语言:…

09C++选择结构(3)——教学

1、求3个整数中最小值; 2、3个数排序; 3、随机函数rand(); 4、if语句的应用; 5、bug与debug一、求3个整数中最小值 题目:输入三个整数,表示梨的重量,输出最小的数。 方法1:经过三次两两比较,得出最小值。 a<=b && a<=c min=ab<=c && b<=a…

趋动云—pycharm连接教程

一、创建项目 二、上传代码 三、启动趋动云虚拟环境四、连接pycharm 1. 打开pycharm,创建项目(上传代码),或者直接打开项目代码 2. 配置在线虚拟环境 (1)点击设置Settings->Python Interpreter->Add Interpreter->On SSH (2)新建在线虚拟环境连接 输入信息:…

校园AI语音识别霸凌监控系统

校园AI语音识别霸凌监控系统通过音频识别技术,校园AI语音识别霸凌监控系统针对校园内监控难以覆盖的区域,如厕所、宿舍、天台等,进行全天候的音频监控。系统通过识别特定的关键词,如“救命”、“老师救我”等,来监测可能发生的霸凌事件。系统采用YOLOv5 AI音频算法,该算法…

校园AI防霸凌报警系统

校园AI防霸凌报警系统利用先进的AI音频分析技术,校园AI防霸凌报警系统能够在没有摄像头的隐私区域,如厕所和宿舍,实时监测异常声音。系统的核心是YOLOv5算法,它能够准确识别出求救声、谩骂声等异常声音,从而触发报警机制。智能防欺凌终端是系统的前线设备,安装在校园的隐…

校园宿舍学生防欺凌检测系统

校园宿舍学生防欺凌检测系统通过在宿舍、卫生间、楼梯角等校园内隐蔽位置安装AI智能语音报警终端。校园宿舍学生防欺凌检测系统通过这些终端麦克风捕捉周围的声音,并将其传输至AI算法模型进行分析。校园宿舍学生防欺凌检测系统能够实时处理语音流,当识别出特定的关键词或短语…

餐厅明厨亮灶实施方案 后厨明厨亮灶监控系统

餐厅明厨亮灶实施方案 后厨明厨亮灶监控系统通过监控摄像机采集后厨人员的监控据,利用AI技术进行数据解决与分析。餐厅明厨亮灶实施方案 后厨明厨亮灶监控系统自动检测识别后厨人员的违规行为,若没有戴厨师帽、口罩、工服等,然后进行抓拍做好记录。系统一旦发现违规行为,立…