re 2023年鹏城杯复现

安全编程:
是rust,我不太想看和调试了
010打开,发现比较有规律,尝试和png头异或得到密钥128
异或出图片

badpe:
这个题的思路之前没见过,居然能这么藏
按照外壳的思路先异或0x23

'''with open("bad_pe.exe","rb") as f:  
    with open("tmp","wb+") as f2:        a= f.read()        for i in a:            f2.write((i^0x23).to_bytes(1,"little"))'''

010打开看看,发现很明显的pe结构,尝试手动修复
删除前面一段数据和末尾一段数据,发现就没有经过其他改动了,尝试运行,果真运行起来了
ida动调,发现是rc4,那就用最简单的构造11111111然后再异或ord(“1”)得到密钥,然后就可以直接解密了


enc=[46,  69, 243, 128, 183, 186,  92, 215,  47, 167,  
  248,  54, 163, 179, 177,  58,  37, 161, 181,  55,  
  151,  32,  28, 108, 185,   4, 126, 134, 158, 155,  
  236,  45, 190,  88, 193,  50, 101, 221,  15, 114,  
  125, 135, 117,  71, 218, 255, 148, 136,  89, 172,  
   11, 104, 142, 252,  23,  87,  78,  63, 152,  18,  
  201,  36,  27,  51,  72,  85,  59, 238, 198,  86,  
   35, 197, 139, 244, 129,   8,  99, 203, 156,  65,  
   82, 166, 119,  56, 100, 216, 157, 173, 217,  95,  
  253, 204,  41, 223, 112, 130, 116,  48,  75, 189,  
  140,  77,  76, 131, 235, 200, 154, 229, 144, 110,  
  123, 150, 115,  61,  91, 170, 240,   3, 145, 171,  
  195,  66, 231, 149, 138, 141,  74, 127, 199, 137,  
  222,  62, 188, 213,   0,  93, 124, 224,  12,  40,  
  247, 225, 175, 169, 132, 176, 102,  83,  31, 226,  
  147,   7,  33,  73, 210, 164, 196,  67, 111,  96,  
   57,   1,  98,  13,  10, 208, 160,  25, 211, 105,  
    9,  16, 106,  81, 207, 245, 230,  38, 122, 205,  
  250, 165, 180, 178, 153,  14,   2,  64, 168, 143,  
   30,  43,  24,  29,  49, 212, 219, 251,  94, 249,  
  182, 113, 107,  21,  60, 233, 209, 146, 241, 254,  
   52,  39,  34, 162,  53, 109,  84, 234, 103, 242,  
  214,   5, 194,  97, 184, 237, 174,  17, 191,  22,  
  192,  19,  26, 187,  70, 239, 232, 228, 120, 133,  
  227, 220, 159, 121,  79, 206,  44,  90,  80,  42,  
  202, 246,  68,   6,  20, 118,   ]  
key=[234, 173,  28, 190, 171,  93, 154, 117,  95, 188,  
  251, 249, 215, 122, 218,  56, 119, 119, 185,  68,  
  192, 132, 211, 175, 191, 177, 143,  22,  42,  76,  
  175,  69, 175,  56, 166]  
key2=[  234, 173,  28, 143, 154, 108, 171,  68, 102, 141,  
  202, 200, 230,  75, 235,   9,  70,  70, 136, 117,  
  241, 181, 226, 158, 142, 128, 190,  39,  27, 125,  
  158, 116,  62,  50,  82]  
key3=[]  
print(len(key)*"1")  
print(0x22)  
strr="th3k3y!"  
for i in range(len(key2)):  
    key3.append(key2[i]^ord("1"))  
print(key3)  
  
real_key=[46,  69, 243, 128, 183, 186,  92, 215,  47, 167,  
  248,  54, 163, 179, 177,  58,  37, 161, 181,  55,  
  151,  32,  28, 108, 185,   4, 126, 134, 158, 155,  
  236,  45, 190,  88, 193,  50, 101, 221,  15, 114,  
  125, 135, 117,  71, 218, 255, 148, 136,  89, 172,  
   11, 104, 142, 252,  23,  87,  78,  63, 152,  18,  
  201,  36,  27,  51,  72,  85,  59, 238, 198,  86,  
   35, 197, 139, 244, 129,   8,  99, 203, 156,  65,  
   82, 166, 119,  56, 100, 216, 157, 173, 217,  95,  
  253, 204,  41, 223, 112, 130, 116,  48,  75, 189,  
  140,  77,  76, 131, 235, 200, 154, 229, 144, 110,  
  123, 150, 115,  61,  91, 170, 240,   3, 145, 171,  
  195,  66, 231, 149, 138, 141,  74,  69, 199, 137,  
  222,  62, 188, 213,   0,  93, 124, 224,  12,  40,  
  247, 225, 175, 169, 132, 176, 102,  83,  31, 226,  
  147,   7,  33,  73, 210, 164, 196,  67, 111,  96,  
   57,   1,  98,  13,  10, 208, 160,  25, 211, 105,  
    9,  16, 106,  81, 207, 245, 230,  38, 122, 205,  
  250, 165, 180, 178, 153,  14,   2,  64, 168, 143,  
   30,  43,  24,  29,  49, 212, 219, 251,  94, 249,  
  182, 113, 107,  21,  60, 233, 209, 146, 241, 254,  
   52,  39,  34, 162,  53, 109,  84, 234, 103, 242,  
  214,   5, 194,  97, 184, 237, 174,  17, 191,  22,  
  192,  19,  26, 187,  70, 239, 232, 228, 120, 133,  
  227, 220, 159, 121,  79, 206,  44,  90,  80,  42,  
  202, 246,  68,   6,  20, 118, ]  
  
print(len(real_key))  
a=[0xe4,0x52,0x9f,0x31,0x89,0x27,0x66,0x67,0xf3,0x68,0x90,0xfc,0xea,0xe5,0x11,0x02,0x5d,0x16,0xab,0x1e,0xe9,0x59,0xd3,0xb4,0x61,0x8d,0x11,0x17,0x19,0xe5,0x88,0x0a,0xcc,0x56,0xde,0x8e,0xd0,0x86,0x3e,0xdc,0x65,0x84,]  
  
for i in a:  
    print((i),end=" ")  
real_enc=[ 189, 240,  76, 217, 208,  41, 242,  70,   8, 204,  
  200, 159, 190,  75, 239, 103,  70,   4, 230,  50,  
  243, 246, 170, 240, 209, 216, 236, 117,  73,  47,  
  204,  38,  46, 126,  99]  
print()  
for i in range(len(real_enc)):  
    print(chr(real_enc[i]^key3[i]),end="")
babyre

先贴脚本

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

int decry1(uint32_t f1, uint32_t f2, uint32_t f3) {
    unsigned int v23, v24, v25;
    uint8_t row[12];
    unsigned int a[32 * 6];
    srand(0xDEADC0DE);

    for (int r = 0; r < 32 * 6; r++) {
        a[r] = rand();
    }

    for (int j = 31; j >= 0; --j) {


        v23 = f1 >> 7;
        v24 = a[4 + j * 6] + v23;
        v25 = (f1 >> 15) ^ (f1 << 10) | 3;
        f3 -= v24 + (a[5 + j * 6] ^ v25);

        v23 = f3 >> 7;
        v24 = a[2 + j * 6] + v23;
        v25 = (f3 >> 15) ^ (f3 << 10) | 3;
        f2 -= v24 + (a[3 + j * 6] ^ v25);

        v23 = f2 >> 7;
        v24 = a[j * 6] + v23;
        v25 = (f2 >> 15) ^ (f2 << 10) | 3;
        f1 -= v24 + (a[1 + j * 6] ^ v25);

        row[0] = (uint8_t)f1;
        row[1] = (uint8_t)(f1 >> 8);
        row[2] = (uint8_t)(f1 >> 16);
        row[3] = (uint8_t)(f1 >> 24);
        row[4] = (uint8_t)f2;
        row[5] = (uint8_t)(f2 >> 8);
        row[6] = (uint8_t)(f2 >> 16);
        row[7] = (uint8_t)(f2 >> 24);
        row[8] = (uint8_t)f3;
        row[9] = (uint8_t)(f3 >> 8);
        row[10] = (uint8_t)(f3 >> 16);
        row[11] = (uint8_t)(f3 >> 24);

        for (int w = 0; w < 12; w++) {
            row[w] = ((row[w] + 0x100 - 66) * 167) % 256;
        }

        f1 = (row[3] << 24) | (row[2] << 16) | (row[1] << 8) | row[0];
        f2 = (row[7] << 24) | (row[6] << 16) | (row[5] << 8) | row[4];
        f3 = (row[11] << 24) | (row[10] << 16) | (row[9] << 8) | row[8];

    }
    printf("%x,%x,%x", f1, f2, f3);

    return 0;
}



int main()
{
    /*uint32_t ida_chars[] = {
      0x484D3BA0, 0x27312854,
      0x6DF12135, 0x18736A4C,
      0x713BBD98, 0xB65A772D,
      0x0B2BCB9B, 0xE48A4CA9,
      0x5C4F1BF1, 0x983D3059,
      0x3F14FC7A, 0xF464022B
    };*/
    uint32_t ida_chars[] = {
    0xA03B4D48,
        0x54283127,
        0x3521F16D,
        0x4C6A7318,
        0x98BD3B71,
        0x2D775AB6,
        0x9BCB2B0B,
        0xA94C8AE4,
        0xF11B4F5C,
        0x59303D98,
        0x7AFC143F,
        0x2B0264F4, };
    decry1(ida_chars[0], ida_chars[1], ida_chars[2]);
    decry1(ida_chars[3], ida_chars[4], ida_chars[5]);
    decry1(ida_chars[6], ida_chars[7], ida_chars[8]);
    decry1(ida_chars[9], ida_chars[10], ida_chars[11]);
    return 0;
}
直接根据逻辑硬逆
具体是srand一个种子,然后用rand生成密钥
还以为给的dllpatch过了,我还自己看了一下dll,发现没有被修改,那就直接调用标准库解密
被大小端序搞了一会儿,最开始写的大端
后来改成小端就出了,但是还要改一下顺序,4位换一下位
flag{1CpOVOIeB1d2FcYUvnN1k5PbfMzMNzUzUgV6mB7hXF}

vm:

这个题,我是赛后复现的,当时不知道怎么做,知道是vm也恢复不出源码,跟着别的师傅的wp复现一下

这是tea的密钥和密文

这里开了10个线程,虽然不知道具体是怎么实现加密的,但是start_routine是虚拟机的使用函数

因为这个指令dump出来有点困难,最开始的想法是通过idapython来打印opcode,但是好像非常的多

import ida_dbg
MyR0 = ida_dbg.get_reg_val("RAX")
print(MyR0,end=",")

手动恢复非常困难,但是由于这里的opcode我导不出来,额,就算导出来了,这里的操作数也不太容易理清,借鉴一下师傅的脚本

#!/usr/bin/env python3

codes = open('./vm', 'rb').read()[0x3020: 0x3020 + 0x157]
codes = ''.join(bin(i)[2: ].rjust(8, '0')[:: -1] for i in codes)

def fetch_imm(codes, pc, size):
    assert pc + size <= len(codes)
    value = int(codes[pc: pc + size][:: -1], 2)
    return value, pc + size

def fetch_opcode(codes, pc):
    return fetch_imm(codes, pc, 5)

def fetch_reg_index(codes, pc):
    return fetch_imm(codes, pc, 4)

def fetch_imm16(codes, pc):
    return fetch_imm(codes, pc, 16)

regs = ['rax', 'rbp', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15']

print('.intel_syntax noprefix')
pc = 0
while pc < len(codes):
    print('_0x%04x: ' % pc, end='')
    opcode, pc = fetch_opcode(codes, pc)
    if opcode == 15:
        dreg, pc = fetch_reg_index(codes, pc)
        imm, pc = fetch_imm16(codes, pc)
        print('cmp %s, 0\n  jnz _0x%04x' % (regs[dreg], imm))
    elif opcode == 17:
        dreg, pc = fetch_reg_index(codes, pc)
        sreg, pc = fetch_reg_index(codes, pc)
        print('mov [%s + 0x2000], %s' % (regs[sreg], regs[dreg]))
    elif opcode == 28:
        print('call m_putchar')
    elif opcode == 29:
        print('call m_getchar')
    elif opcode == 31:
        print('ret')
    elif opcode == 16:
        dreg, pc = fetch_reg_index(codes, pc)
        sreg, pc = fetch_reg_index(codes, pc)
        print('mov %s, [%s + 0x2000]' % (regs[dreg], regs[sreg]))
    elif opcode & 0x18 == 8:
        dreg, pc = fetch_reg_index(codes, pc)
        imm, pc = fetch_imm16(codes, pc)
        op = ['add', 'sub', 'mov', 'shl', 'shr'][opcode & 7]
        print('%s %s, 0x%x' % (op, regs[dreg], imm))
    elif opcode & 0x18 == 0:
        dreg, pc = fetch_reg_index(codes, pc)
        sreg, pc = fetch_reg_index(codes, pc)
        op = ['add', 'sub', 'mov', 'xor'][opcode & 7]
        print('%s %s, %s' % (op, regs[dreg], regs[sreg]))
    else:
        assert False, hex(opcode)

第一次见这样的代码,太高级了,这样恢复虚拟机真的好用,然后再gcc -s main.s -o main.o

然后放ida中分析,就是一个很清晰的tea加密了,太nb了,学习了

然后解密就是小问题了,网上一找一堆

#include <stdio.h>
#include <stdint.h>

//加密函数
void encrypt(uint32_t* v, uint32_t* k) {
	uint32_t v0 = v[0], v1 = v[1], sum = 0, i;
	uint32_t delta = 0x9e3779b9;
	uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
	for (i = 0; i < 32; i++) {
		sum += delta;
		v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
		v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
	}
	v[0] = v0; v[1] = v1;
}

//解密函数
void decrypt(uint32_t* v, uint32_t* k) {
	uint32_t v0 = v[0], v1 = v[1], sum = 0, i;
	uint32_t delta = 0x43217856;
	sum=delta*32;
	uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
	for (i = 0; i<32; i++) {
		v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
		v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
		sum -= delta;
	}
	v[0] = v0; v[1] = v1;
}

int main()
{
	int i=0;
	int j=0; 
	// v为要加解密的数据,两个32位无符号整数
	uint32_t v[] = { 0x0FB6B1B8,0x3A84F414,0x90CE01CB,0xB4859002,0xEA807F7C,0x2D7458B7 };
	uint32_t v1[]={0x90CE01CB,0xB4859002};
	uint32_t v2[]={0xEA807F7C,0x2D7458B7};
	// k为加解密密钥,4个32位无符号整数,密钥长度为128位
	uint32_t k[4] = { 17,34,136,0xff};
	int n = sizeof(v) / sizeof(uint32_t);
	printf("加密前原始数据:0x%x 0x%x\n", v[0], v[1]);
	//encrypt(v, k);
	printf("加密后的数据:0x%x 0x%x\n", v[0], v[1]);
	decrypt(v1, k);
	//decrypt(v[2], k);
	//decrypt(v[4], k);
	printf("解密后的数据:0x%x 0x%x\n", v[0], v[1]);
	for ( i = 0; i < n; i++)
	{
		for ( j = 0; j < sizeof(uint32_t)/sizeof(uint8_t); j++)
		{
			printf("%c", (v1[i] >> (j * 8)) & 0xFF);
		}
	}
	printf("\n");
	return 0;
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值