DubheCTF2024 | Reverse (3道)

ezVK

涨姿势了...
信息收集 Vulcan && SPIRV-Tools
关键是怎么提取资源
动调跟到这里

image

image

一个是起始位置一个是大小 提取出来写入dumpp

import idaapi

# Function to dump memory range to a file
def dump_memory(start_addr, size, file_path):
    # Open the file for writing in binary mode
    with open(file_path, "wb") as f:
        # Iterate over each byte in the range and write it to the file
        for i in range(size):
            # Read a byte from the current address
            byte = idaapi.get_byte(start_addr + i)
            # Write the byte to the file
            f.write(byte.to_bytes(1, 'little'))

        print(f"Dumped memory range from {hex(start_addr)} to {hex(start_addr + size)} into {file_path}")

# Example usage:
# Replace 'start_addr' with the starting address of the memory range you want to dump
# Replace 'size' with the size of the memory range in bytes
# Replace 'output_file_path' with the path to the file where you want to write the memory dump
start_addr = 0x7FF6063AA1D0  # Replace with the actual start address
size = 0xDB4  # Replace with the actual size
output_file_path = "E:\\memory_dump.bin"  # Replace with your desired file path

# Call the function to perform the memory dump
dump_memory(start_addr, size, output_file_path)

然后kali安装spirv-cross

image

得到代码:

image

#version 450
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

const uint _80[5] = uint[](1214346853u, 558265710u, 559376756u, 1747010677u, 1651008801u);

layout(binding = 0, std430) buffer V
{
    uint v[];
} _23;

void main()
{
    uint cnt = gl_GlobalInvocationID.x * 2u;
    uint sum = 0u;
    uint l = _23.v[cnt];
    uint r = _23.v[cnt + 1u];
    for (int i = 1; i <= 40; i++)
    {
        l += ((((((~(r << uint(3))) & (r >> uint(5))) | ((r << uint(3)) & (~(r >> uint(5))))) ^ (~r)) & ((r << uint(3)) ^ (r >> uint(5)))) ^ ((~((~(sum + _80[sum & 4u])) | (~((r >> uint(3)) & (r << uint(2)))))) & (l | (~l))));
        sum += 1932555628u;
        r += ((((((~(l << uint(3))) & (l >> uint(5))) | ((l << uint(3)) & (~(l >> uint(5))))) ^ (~l)) & ((l << uint(3)) ^ (l >> uint(5)))) ^ ((~((~(sum + _80[(sum >> uint(11)) & 4u])) | (~((l >> uint(3)) & (l << uint(2)))))) & (r | (~r))));
    }
    _23.v[cnt] = l;
    _23.v[cnt + 1u] = r;
}


类tea系列 逆向即可

#include<bits/stdc++.h>
#include<stdint.h>
using namespace std;
//#define unsigned int unsigned int
void dec(unsigned int v[2],unsigned int key[]){
	unsigned int DELTA = 1932555628u;
	unsigned int sum = 40*DELTA;
	unsigned int l = v[0],r = v[1];
	for (int i = 1; i <= 40; i++)
    {
//        l += ((((((~(r << unsigned int(3))) & (r >> unsigned int(5))) | ((r << unsigned int(3)) & (~(r >> unsigned int(5))))) ^ (~r)) & ((r << unsigned int(3)) ^ (r >> unsigned int(5)))) ^ ((~((~(sum + _80[sum & 4u])) | (~((r >> unsigned int(3)) & (r << unsigned int(2)))))) & (l | (~l))));
//        sum += 1932555628u;
//        r += ((((((~(l << unsigned int(3))) & (l >> unsigned int(5))) | ((l << unsigned int(3)) & (~(l >> unsigned int(5))))) ^ (~l)) & ((l << unsigned int(3)) ^ (l >> unsigned int(5)))) ^ ((~((~(sum + _80[(sum >> unsigned int(11)) & 4u])) | (~((l >> unsigned int(3)) & (l << unsigned int(2)))))) & (r | (~r))));
    	r -= ((((((~(l << (3))) & (l >>  (5))) | ((l << (3)) & (~(l >> (5))))) ^ (~l)) & ((l << (3)) ^ (l >> (5)))) ^ ((~((~(sum + key[(sum >> (11)) & 4u])) | (~((l >> (3)) & (l << (2)))))) & (r | (~r))));
		sum -= DELTA;
		l -= ((((((~(r << (3))) & (r >> (5))) | ((r << (3)) & (~(r >> (5))))) ^ (~r)) & ((r <<  (3)) ^ (r >> (5)))) ^ ((~((~(sum + key[sum & 4u])) | (~((r >> (3)) & (r << (2)))))) & (l | (~l))));
	}
	v[0] = l;
	v[1] = r;
}
signed main(){
	unsigned int key[] = {1214346853u, 558265710u, 559376756u, 1747010677u, 1651008801u};
	unsigned int v[] = {0x185B72AF, 0x0631D2C6, 0xDE8B33CC, 0x31EBCD9F, 0x05DB8B33, 0x0A8D77D0, 0x865C6111, 0xBF032335, 
    0x722228A5, 0xAD833A57, 0xB7C3456F,0}	;
   	for(int i=0;i<6;i++){
   		dec((unsigned int*)(v+2*i),key);
	   }
	for(int i=0;i<11;i++)cout<<v[i]<<",";
}

python n2s转一下
DubheCTF{Go0Od!!!You_4re_Vu1k@N_Mast3r^^补上}发现还差一位 爆破即可...

DubheCTF{Go0Od!!!You_4re_Vu1k@N_Mast3r^^_}



跟Google2017那道moon很相似~ 都使用了着色器代码..

VMT

一堆反调试 IDApatch不干净 直接sharpod过
CFF把dll can move去掉
输入完过后触发了一大堆异常

调着调着密文就出现了

image

还有N0ThisiS4F4k3K3Y变化后的密钥

image

image

但是这里调不进去? 一直在触发异常....
后面发现可以把x32的db删掉 然后只在这个函数处下断点 重新F9就可以断下了
 

image


调试时发现把我们输入的ascii都转成了hex拼接

substr:

image

一堆datacopy 调了调发现分别取了input的四段

image

sub_4031B0 跟进去发现其实就是一个按位xor

image

xor完后注意这里

image

跟进去

image

继续跟进
很长的一个函数
注意到结尾处

image

结合前面的大致能猜到是在生成一个表
x32动调看

image

熟悉的table google一下

image

SM4
我们已经知道密文密钥 直接cyberchef一把梭

image

DubheCTF{VMT_H00K_4ND_$3H_15_U53FUL}



这里不得不%一下Ysiel学长
手撕SM4 orz

image

Destination

一大堆花指令混淆
两种思路:

  1. trace打印指令流分析
  2. patch花指令

trace方法跟着试了试并没有太成功 最后打印出来感觉不全...
DubheCTF2024 Writeup - 星盟安全团队

那就硬patch花指令吧
大致看看影响反编译的花指令

image

image

image

也就是
E8 00 00 00 00 83 04 24 05 C3 这串
直接nop即可
但注意到还有这种
 

image


nop前面的同时还要
对后面 0F 84 0F 85 这种跳转指令进行处理
以上面图为例 我们把0F 84 48 17 00 00 nop掉
如果是 0F 85 0F 84 就直接nop后jmp 后面不用管
同时也理解了jz jnz机器码的意义
 

image


跳转地址采用的是相对PC的寻址
0x414350+0x6+0xA2 == 0x414356+0x6+0x9C == 0x4143F8
脚本如下:

from tqdm import *
binfile = open("Destination.exe","rb").read()

founds = []
index = binfile.find(b'\xE8\x00\x00\x00\x00\x83\x04\x24\x05\xC3')
# find all junkcode
while index!=-1:
    founds.append(index)
    index = binfile.find(b'\xE8\x00\x00\x00\x00\x83\x04\x24\x05\xC3',index+1) #! index+1 ! 不然死循环了...
    print(index)
    
binfile = bytearray(binfile)
print(len(founds))
# replace all matches

for found in founds:
    patch = ["nop"]*10 # call $+5 这一段可以全部nop
    instr = binfile[found+10:found+12]
    # 处理 jnz jz 花指令
    if instr == b'\x0F\x84' or instr == b'\x0F\x85':
        if instr == b'\x0F\x84':
            patch += ["nop"]*6 # 把jnz全部nop
        elif instr == b'\x0F\x85':
            patch += ["nop","jmp"]+["pass"]*4
        next_instr = binfile[found+16:found+18]
        if next_instr == b'\x0F\x84' or next_instr == b'\x0F\x85':
            if next_instr == b'\x0F\x84':
                patch += ["nop"]*6 # 把jnz全部nop
            elif next_instr == b'\x0F\x85':
                patch += ["nop","jmp"]+["pass"]*4
    
    for i in range(len(patch)): # 替换回机器码
        if patch[i] == "nop":
            binfile[found+i] = 0x90
        elif patch[i] == "jmp":
            binfile[found+i] = 0xE9

open("Patched_Destination.exe","wb").write(binfile)

image

然后在4140D7处有一堆jmp跳转
 

image


一次指令一次jmp...
处理后反编译得到

int sub_4140D7()
{
  unsigned int v0; // ecx
  unsigned int v3; // [esp+0h] [ebp-10Ch]
  unsigned int v4; // [esp+C8h] [ebp-44h]
  unsigned int v5; // [esp+D4h] [ebp-38h]
  int v6; // [esp+ECh] [ebp-20h]
  unsigned int i; // [esp+F8h] [ebp-14h]
  int v8; // [esp+104h] [ebp-8h]

  v8 = 50;
  v4 = 0;
  v5 = dword_4234A8[11];
  do
  {
    v4 -= 1531682718;
    v6 = (v4 >> 2) & 3;
    for ( i = 0; i < 0xB; ++i )
    {
      v3 = (((v5 ^ dword_42309C[v6 ^ i & 3]) + (dword_4234AC[i] ^ v4)) ^ (((16 * v5) ^ ((unsigned int)dword_4234AC[i] >> 3))
                                                                        + ((4 * dword_4234AC[i]) ^ (v5 >> 5))))
         + dword_4234A8[i];
      dword_4234A8[i] = v3;
      v5 = v3;
    }
    v0 = (((v5 ^ dword_42309C[v6 ^ i & 3]) + (dword_4234A8[0] ^ v4)) ^ (((16 * v5) ^ ((unsigned int)dword_4234A8[0] >> 3))
                                                                      + ((4 * dword_4234A8[0]) ^ (v5 >> 5))))
       + dword_4234A8[11];
    dword_4234A8[11] = v0;
    v5 = v0;
  }
  while ( --v8 );
  return 1;
}

还有一个sub_413F77

void __usercall sub_413F77(int a1@<eax>, int a2@<ecx>, int a3@<ebp>)
{
  int v3; // ecx
  int v4; // eax
  unsigned int v5; // esi
  unsigned int v6; // edi
  int v7; // ecx
  unsigned int v8; // esi

  v3 = a2 + 2;
  v4 = a1 - 1;
  while ( 1 )
  {
    --a3;
    v5 = 0;
    do
    {
      v6 = v5 >> 31;
      v7 = v3 - 3;
      if ( v5 >> 31 == 1 )
        v8 = (2 * v5) ^ 0x84A6972F;
      else
        v8 = 2 * v5;
      v5 = v8 + 1;
      v3 = v7 - 2;
    }
    while ( v5 != 32 );
    dword_4234A8[v6] = 32;
    v4 -= 2;
    if ( v6 == 11 )
      __asm { retf }
  }
}

exp直接搬了...

import struct
from ctypes import c_uint32
 
DELTA = 0xa4b46062
 
 
def encrypt(v, n, k):
    # rounds = 6 + int(52 / n)
    rounds = 50
    sum = c_uint32(0)
    z = v[n - 1].value
    while rounds > 0:
        sum.value += DELTA
        e = (sum.value >> 2) & 3
        p = 0
        while p < n - 1:
            y = v[p + 1].value
            v[p].value += (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum.value ^ y) + (k[(p & 3) ^ e] ^ z)))
            z = v[p].value
            p += 1
        y = v[0].value
        v[n - 1].value += (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum.value ^ y) + (k[(p & 3) ^ e] ^ z)))
        z = v[n - 1].value
        rounds -= 1
 
 
def decrypt(v, n, k):
    rounds = 50
    sum = c_uint32(rounds * DELTA)
    y = v[0].value
    while rounds > 0:
        e = (sum.value >> 2) & 3
        p = n - 1
        while p > 0:
            z = v[p - 1].value
            v[p].value -= (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum.value ^ y) + (k[(p ^ e) & 3] ^ z)))
            y = v[p].value
            p -= 1
        z = v[n - 1].value
        v[0].value -= (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum.value ^ y) + (k[(p ^ e) & 3] ^ z)))
        y = v[0].value
        sum.value -= DELTA
        rounds -= 1

def xormul(x, y):
    product = 0
    for i in range(len(bin(y)) - 2):
        if (y & 1) != 0:
            product ^= (x << i)
        y >>= 1
    return product

def xord(x):
    product = x
    for i in range(32):
        if (product >> 31) & 1 != 0:
            product <<= 1
            product ^= 0x84A6972F
        else: product <<= 1
        product &= 0xFFFFFFFF
    return product

def rexord(x):
    product = x
    for i in range(32):
        if product & 1 != 0:
            product ^= 0x84A6972F
            product >>= 1
            product ^= 0x80000000
        else: product >>= 1
    return product

print(hex(xord(0x98c3aeba)))
print()
print(hex(0b11101111101001001110100101100111))
print(hex(rexord(0xa755690)))
1100101

def xordivmod(x, y):
    div = 0
    while len(bin(x)) >= len(bin(y)) and x != 0:
        div ^= 1 << (len(bin(x)) - len(bin(y)))
        x ^= y << (len(bin(x)) - len(bin(y)))
    return div, x

def extended_gcd(a, b):
    if a == 0:
        return (b, 0, 1)
    else:
        div, mod = xordivmod(b, a)
        gcd, x, y = extended_gcd(mod, a)
        return (gcd, y ^ xormul(div, x), x)

def mod_inverse(a, m):
    gcd, x, y = extended_gcd(a, m)
    if gcd != 1:
        raise ValueError(f"The modular inverse does not exist for {a} mod {m}")
    else:
        return xordivmod(x, m)

print(hex(xormul(0x84A6972F, 1536173203) & 0xFFFFFFFF))
print(hex(xormul(0x84A6972F, 0x98c3aeba) & 0xFFFFFFFF))
print(hex((0x84A6972F * 0x98c3aeba) & 0xFFFFFFFF))
print(mod_inverse(0x84a6972f, 0x100000000))

 
 
def test1():
    k = [1796110955, 3509588462, 2816552045, 3248073894]
    v = [c_uint32(2811296470),
        c_uint32(3905462903),
        c_uint32(3473114362),
        c_uint32(778862551),
        c_uint32(1832097419),
        c_uint32(1532477991),
        c_uint32(1698473566),
        c_uint32(2244407804),
        c_uint32(3790808439),
        c_uint32(3570904694),
        c_uint32(1068461508),
        c_uint32(223976844),]
    v = [c_uint32(rexord(i.value)) for i in v]
    decrypt(v, len(v), k)
    decrypt(v, len(v), k)
    print(b''.join([i.value.to_bytes(4, 'little') for i in v]))

def test2():
    k = [1796110955, 3509588462, 2816552045, 3248073894]
    v = [c_uint32(1684234849),
        c_uint32(1751606885),
        c_uint32(1818978921),
        c_uint32(1886350957),
        c_uint32(1953722993),
        c_uint32(2021095029),
        c_uint32(842103417),
        c_uint32(909456435),
        c_uint32(809056311),
        c_uint32(875770417),
        c_uint32(943142453),
        c_uint32(57),]
    encrypt(v, len(v), k)
    encrypt(v, len(v), k)
    print([hex(i.value) for i in v])

def test3():
    k = [1796110955, 3509588462, 2816552045, 3248073894]
    v = [c_uint32(2166517392), c_uint32(2308814115), c_uint32(907928798), c_uint32(416155181), c_uint32(2478635997), c_uint32(2992052781), c_uint32(2761723689), c_uint32(4081200924), c_uint32(3375441825), c_uint32(3740218937), c_uint32(3731001390), c_uint32(2820357446)]
    decrypt(v, len(v), k)
    print(b''.join([i.value.to_bytes(4, 'little') for i in v]))

test1()
test2()

test3()

DubheCTF{82e1e3f8-85fe469f-8499dd48-466a9d60}

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值