1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
extern crate byteorder;

use std::num::Wrapping;

use byteorder::LittleEndian;
use byteorder::ByteOrder;
use byteorder::WriteBytesExt;

static STATIC_KEY: Wrapping<u64> = Wrapping(0x8FEB2A6740A6920E);

pub fn decrypt_table(ciphertext: &Vec<u8>, verbose: bool) -> Vec<u8> {
    let mut plaintext = Vec::with_capacity(ciphertext.len());
    let mut edi: u32 = 0;
    let mut esi = 0;
    let mut eax;
    let mut edx;
    for _ in 0..ciphertext.len()/8 {
        // push 0x8FEB2A67
        // push 0x40A6920E
        // mov eax, edi
        // not eax
        // push 0
        // push eax
        // call multiply
        let prod = (STATIC_KEY * Wrapping((!edi) as u64)).0;
        if verbose {
            println!("prod: {:X}", prod);
        }
        eax = prod as u32;
        edx = (prod >> 32) as u32;
        if verbose {
            println!("eax: {:X}", eax);
            println!("edx: {:X}", edx);
        }

        // xor eax, [ebx+esi]
        eax ^= LittleEndian::read_u32(&ciphertext[esi..esi + 4]);
        if verbose {
            println!("eax: {:X}", eax);
        }

        // add edi, 8
        edi += 8;

        // xor edx, [ebx+esi+4]
        let _edx = LittleEndian::read_u32(&ciphertext[esi + 4..esi + 8]);
        if verbose {
            println!("_edx {:X}", _edx);
        }
        edx ^= _edx;
        if verbose {
            println!("edx {:X}", edx);
        }

        // mov [esi], eax
        plaintext.write_u32::<LittleEndian>(eax).unwrap();

        // mov [esi+4], edx
        if verbose {
            println!("{:X}", edx);
        }
        plaintext.write_u32::<LittleEndian>(edx).unwrap();
        esi += 8;
    }
    plaintext
}