re Pengcheng Cup returns in 2023

Secure programming:
It’s rust, and I don’t really want to look at it and debug it.
Open 010 and find that it is more regular. Try XOR with the png header to get the key 128.
XOR out the picture

badpe:
I have never seen the idea of this question before, but it can be hidden like this
According to the idea of the shell, first XOR 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 Open it and take a look. You will find an obvious PE structure and try to repair it manually.
Delete the previous piece of data and the last piece of data, and find that there are no other changes. I try to run it, and it really works.
Ida is adjusted and found to be rc4. Then use the simplest construction 11111111 and then XOR ord (“1”) to get the key, and then you can directly decrypt it.

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="")
<strong>babyre</strong>

Post the script first

#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;
}
Direct inversion based on logic
Specifically, srand a seed, and then use rand to generate a key
I thought the dll was patched, so I looked at the dll myself and found that it had not been modified, so I directly called the standard library to decrypt it.
I was confused about the big and small endian order for a while, and I first wrote the big endian
Later, it was changed to little endian and it came out, but the order had to be changed, and the 4 digits were changed.
flag{1CpOVOIeB1d2FcYUvnN1k5PbfMzMNzUzUgV6mB7hXF}

vm:

I reproduced this problem after the game. I didn’t know how to do it at the time. Even though I knew it was vm, I couldn’t restore the source code. So I reproduced it using other masters’ wp.

This is tea’s key and ciphertext

There are 10 threads opened here. Although I don’t know how encryption is implemented, start_routine is a function used by the virtual machine.

Because it is a bit difficult to dump this command, the initial idea was to print the opcode through idapython, but there seemed to be too many

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

Manual recovery is very difficult, but I can’t export the opcode here. Well, even if I export it, the operands here are not easy to sort out. Let’s learn from the master’s script.

#!/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 x: ' % 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\\
 jnz _0x x' % (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 & amp; 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 & amp; 7]
        print('%s %s, %s' % (op, regs[dreg], regs[sreg]))
    else:
        assert False, hex(opcode)

This is the first time I have seen such code. It is too advanced. It is really easy to restore the virtual machine in this way. Then use gcc -s main.s -o main.o

Then put it in ida for analysis. It is a very clear tea encryption. It is so nb. I have learned a lot.

Then decryption is a small problem. I can find a lot of them online.

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

//encryption function
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;
}

//decryption function
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 is the data to be encrypted and decrypted, two 32-bit unsigned integers
uint32_t v[] = { 0x0FB6B1B8,0x3A84F414,0x90CE01CB,0xB4859002,0xEA807F7C,0x2D7458B7 };
uint32_t v1[]={0x90CE01CB,0xB4859002};
uint32_t v2[]={0xEA807F7C,0x2D7458B7};
//k is the encryption and decryption key, four 32-bit unsigned integers, the key length is 128 bits
uint32_t k[4] = { 17,34,136,0xff};
int n = sizeof(v) / sizeof(uint32_t);
printf("Original data before encryption: 0x%x 0x%x\\
", v[0], v[1]);
//encrypt(v, k);
printf("Encrypted data: 0x%x 0x%x\\
", v[0], v[1]);
decrypt(v1, k);
//decrypt(v[2], k);
//decrypt(v[4], k);
printf("Decrypted data: 0x%x 0x%x\\
", 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)) & amp; 0xFF);
}
}
printf("\\
");
return 0;
}