driver复现(铁三2024)

# PREFACE:之前看了不少驱动开发,然后发现这题调不起来,静态解不出来,赛后速通 unicorn 写了个模拟看看

首先,可以看到文件的前 0x400 字符是文件头信息,先 rebase+0x400

这里直接贴一个 unicorn 脚本,可以看到 tea 的操作,前后转化了一次端序然后标准 TEA, which is WRONG:

from unicorn import *
from unicorn.x86_const import *
import struct
from capstone import *
REAL_BASE_OFFSET = 0x400
md = Cs(CS_ARCH_X86, CS_MODE_64)
def read(name):
    with open(name,'rb') as f:
        return f.read()
def hookDbgPrint(mu,address,size,user_data):
    code = mu.mem_read(address, size)
    # for instruction in md.disasm(code, address):
    #     print("0x%x: %s %s" % (instruction.address, instruction.mnemonic, instruction.op_str))
    DbgList = [0x1400015C9]
    if (address in DbgList):
        mu.reg_write(UC_X86_REG_RIP, address+5)
        print(f"hook: {address}")
    if (address == 0x140001940):
        TEAoutput = mu.mem_read(mu.reg_read(UC_X86_REG_RAX), 32)
    if (address == 0x1400017DB):
        # mu.mem_write(mu.reg_read(UC_X86_REG_RSP) + 40, b'12345678')
        TEAinput = mu.mem_read(mu.reg_read(UC_X86_REG_RSP) + 40, 8)
        print("tea in: ",bytes(TEAinput))
    if (address == 0x14000166D):
        mu.mem_write(mu.reg_read(UC_X86_REG_RSP) + 144, b'12345678')
    if (address == 0x14000182D):
        TEAoutput = mu.mem_read(mu.reg_read(UC_X86_REG_RSP) + 40, 8)
        print("tea out: ",end='')
        for i in TEAoutput:
            print(i,end=',')
        print()
    if (address == 0x14000197A):
        ENCoutput = mu.mem_read(mu.reg_read(UC_X86_REG_RSP) + 40, 8)
        print("enc out:",end='')
        for i in ENCoutput:
            print(i,end=',')
        print()
def hookEND(mu : Uc,address,size,user_data):
    if (address == 0x14000197A):
        print("end")
        # exit(0)
        mu.emu_stop()
mu = Uc (UC_ARCH_X86, UC_MODE_64)
BASE = 0x140001000
STACK_ADDR = 0x1000
STACK_SIZE = 1024*1024
mu.mem_map(BASE, 1024*1024)
mu.mem_map(STACK_ADDR, STACK_SIZE)
mu.mem_write(BASE, read("./ez_driver.sys"))
mu.reg_write(UC_X86_REG_RBP, STACK_ADDR + STACK_SIZE // 2)
mu.reg_write(UC_X86_REG_RSP, STACK_ADDR + STACK_SIZE // 3)
mu.hook_add(UC_HOOK_CODE,hookDbgPrint)
mu.hook_add(UC_HOOK_CODE,hookEND)
mu.emu_start(0x14000161D, 0x140004000)

另一个加密就是对称的,其实看了就知道只做了 xor,重写一遍就行:

#include <iostream>
#include <Windows.h>
BYTE byte_140004000[] =
{
	0x72, 0x62, 0xAE, 0x34, 0x52, 0x9A, 0x06, 0xAF, 
	0x72, 0xFB, 0x40, 0xC0, 0x10, 0x35, 0xBD, 0xD4,
	0x22, 0xA5, 0x93, 0x07, 0xB4, 0xFB, 0xB5, 0xCA,
	0xE8, 0x01, 0xF5, 0xAE, 0xED, 0x7B, 0xB8, 0x6A
};
__int64 __fastcall sub_140001A70(unsigned int *input, int a2)
{
	int j; // [rsp+4h] [rbp-44h]
	int i; // [rsp+8h] [rbp-40h]
	unsigned int input_xor; // [rsp+Ch] [rbp-3Ch] BYREF
	unsigned char *p_input_xor; // [rsp+10h] [rbp-38h]
	unsigned int v6; // [rsp+18h] [rbp-30h]
	char v7[16]; // [rsp+20h] [rbp-28h]
	
	v7[1] = a2 ^ 0x25;
	v7[0] = a2 ^ 0x7A;
	v7[8] = a2 ^ 0x1A;
	v7[2] = a2 ^ 0x35;
	v7[9] = a2 ^ 0x6D;
	v7[3] = a2 ^ 0x23;
	v7[11] = a2 ^ 0x94;
	v7[4] = a2 ^ 0xC5;
	v7[5] = a2 ^ 0x4B;
	v7[6] = a2 ^ 0x21;
	v7[7] = a2 ^ 0x35;
	v7[10] = a2 ^ 0x91;
	v7[12] = a2 ^ 0x2C;
	v7[13] = a2 ^ 0xC1;
	v7[14] = a2 ^ 0x92;
	v7[15] = a2 ^ 0x51;
	for ( i = 0; i < 4; ++i )
	{
		p_input_xor = (unsigned char*)&input_xor;
		input_xor = *input ^ a2;
		for ( j = 0; j < 4; ++j )
			*p_input_xor++ ^= v7[15 - (((unsigned __int8)i + (unsigned __int8)j) & 0xF)] | ((unsigned __int8)j << j) | j | 4;
		v6 = ~a2 ^ input_xor;
		*input++ = v6;
	}
}
int main()
{
	int v8 = 0;
	BYTE* v17 = byte_140004000;
	do
	{
		sub_140001A70((unsigned int *)v17, v8++);
		v17 += 16;
	} while (v8 < 2);
	for (unsigned char c : byte_140004000)
		printf("%d,", c);
	printf("\n");
}

然后发现模拟结果和解密明明对得上,但是出不来,结论是藏东西了或者改东西了,毕竟没有真起起来调,然后发现前面有这个 init,寻找特定的结构 shr ecx, 0x5,把 5 改成 6

image

土里刨一个脚本出来:

#include<bits/stdc++.h>
using namespace std;
void decrypt(uint32_t *v, uint32_t *key)
{
	uint32_t l = v[0], r = v[1], sum = 0x9E3779B9 * 33;
	for (int i = 0; i < 33; ++i)
	{
		r -= (key[(sum >> 11) & 3] + sum) ^ (l + ((l >> 5) ^ (16 * l)));
		sum += 0x61C88647;
		l -= (key[sum & 3] + sum) ^ (r + ((r >> 6) ^ (16 * r)));
		
	}
	v[0] = l, v[1] = r;
}
int main(){
	uint32_t key[4];
	// 加解密对称!!!
//	uint8_t enc[] = {0x72, 0x62, 0xAE, 0x34, 0x52, 0x9A, 0x06, 0xAF, 
//							0x72, 0xFB, 0x40, 0xC0, 0x10, 0x35, 0xBD, 0xD4,
//							0x22, 0xA5, 0x93, 0x07, 0xB4, 0xFB, 0xB5, 0xCA,
//							0xE8, 0x01, 0xF5, 0xAE, 0xED, 0x7B, 0xB8, 0x6A};
	uint8_t enc[] = {216,10,158,244,59,162,215,207,72,43,33,160,195,93,221,84,137,205,162,199,220,195,101,170,211,209,149,206,63,19,217,234};
	key[0] = 0x1A2B;
	key[1] = 0x3A4D;
	key[2] = 0x5E6F;
	key[3] = 0xAA33;
	for (int i=0;i<32;i+=8){
		uint32_t *p = (uint32_t *)&enc[i];
		p[0] = __builtin_bswap32(p[0]);
		p[1] = __builtin_bswap32(p[1]);
		decrypt((uint32_t*)p,key);
		p[0] = __builtin_bswap32(p[0]);
		p[1] = __builtin_bswap32(p[1]);
	}
	for (int i=0;i<32;i++){
		printf("%c",enc[i]);
	}
	return 0;
}