mirror of https://github.com/UMSKT/peacestone.git
update
This commit is contained in:
parent
dee5bf889f
commit
cf89342b36
144
notes.txt
144
notes.txt
|
@ -1,4 +1,15 @@
|
|||
; Obfuscated jmp structure
|
||||
NOTES
|
||||
|
||||
These are observations made while looking through WARBIRD code.
|
||||
|
||||
Some are relevant to deobfuscation, while some are just oddities and curiosities.
|
||||
|
||||
Hopefully, once I have a better understanding of everything, these notes will look a lot nicer!
|
||||
|
||||
===========================================================
|
||||
|
||||
Obfuscated jmp structure
|
||||
|
||||
; where reg is one of: eax, ecx, edx, ebx, ebp, esi, edi
|
||||
|
||||
; push is sometimes replaced with the following equivalent instructions
|
||||
|
@ -6,7 +17,7 @@
|
|||
; mov [esp], reg
|
||||
|
||||
; IDA (and perhaps other disassemblers idk) confuses the first parts of the stub for constant bytes
|
||||
; This combined with the random push replacement will make the stub look different, but its infact always the same
|
||||
; This combined with the random instruction replacement will make the stub look different, but its infact always the same
|
||||
|
||||
push reg
|
||||
push reg
|
||||
|
@ -27,18 +38,32 @@ ret 4
|
|||
; after verifier finishes, it adds 0x10 to the value at [esp]
|
||||
; now esp points to the target jump address, and another ret is done to "return" to it
|
||||
|
||||
; rarely (~1% of the time), the last three instructions are replaced with:
|
||||
; xchg [esp], reg
|
||||
; ret
|
||||
; the principle of operation and results are the same, except only 2 values are placed on the stack
|
||||
|
||||
; =======BYTE MARKERS=======
|
||||
;
|
||||
mov reg, [esp+4]
|
||||
ret 4
|
||||
; eax - 8b 44 24 04 c2 04 00
|
||||
; ecx - 8b 4c 24 04 c2 04 00
|
||||
; edx - 8b 54 24 04 c2 04 00
|
||||
; ebx - 8b 5c 24 04 c2 04 00
|
||||
; ebp - 8b 6c 24 04 c2 04 00
|
||||
; esi - 8b 74 24 04 c2 04 00
|
||||
; edi - 8b 7c 24 04 c2 04 00
|
||||
;
|
||||
; Useful for finding obfuscated jumps in a disassembler
|
||||
|
||||
lea esp, [esp - 4]
|
||||
mov [esp], reg
|
||||
; eax - 8d 64 24 fc 89 04 24
|
||||
; ecx - 8d 64 24 fc 89 0c 24
|
||||
; edx - 8d 64 24 fc 89 14 24
|
||||
; ebx - 8d 64 24 fc 89 1c 24
|
||||
; ebp - 8d 64 24 fc 89 2c 24
|
||||
; esi - 8d 64 24 fc 89 34 24
|
||||
; edi - 8d 64 24 fc 89 3c 24
|
||||
|
||||
push reg
|
||||
; eax - 50
|
||||
; ecx - 51
|
||||
; edx - 52
|
||||
; ebx - 53
|
||||
; ebp - 55
|
||||
; esi - 56
|
||||
; edi - 57
|
||||
|
||||
; 0x11223344 is an example address
|
||||
lea reg, [0x11223344]
|
||||
|
@ -49,3 +74,96 @@ lea reg, [0x11223344]
|
|||
; ebp - 8d 2d 44 33 22 11
|
||||
; esi - 8d 35 44 33 22 11
|
||||
; edi - 8d 3d 44 33 22 11
|
||||
|
||||
mov reg, [esp+4]
|
||||
ret 4
|
||||
; eax - 8b 44 24 04 c2 04 00
|
||||
; ecx - 8b 4c 24 04 c2 04 00
|
||||
; edx - 8b 54 24 04 c2 04 00
|
||||
; ebx - 8b 5c 24 04 c2 04 00
|
||||
; ebp - 8b 6c 24 04 c2 04 00
|
||||
; esi - 8b 74 24 04 c2 04 00
|
||||
; edi - 8b 7c 24 04 c2 04 00
|
||||
|
||||
xchg [esp], reg
|
||||
ret
|
||||
; eax - 87 04 24 c3
|
||||
; ecx - 87 0c 24 c3
|
||||
; edx - 87 14 24 c3
|
||||
; ebx - 87 1c 24 c3
|
||||
; ebp - 87 2c 24 c3
|
||||
; esi - 87 34 24 c3
|
||||
; edi - 87 3c 24 c3
|
||||
|
||||
===========================================================
|
||||
|
||||
Hidden functions in CRT initialization
|
||||
|
||||
Upon launch, msvcrt will run a list of functions to initialize the C++ runtime like so:
|
||||
|
||||
static bool __cdecl initialize_c()
|
||||
{
|
||||
_initialize_onexit_table(&__acrt_atexit_table);
|
||||
_initialize_onexit_table(&__acrt_at_quick_exit_table);
|
||||
|
||||
// Do C initialization:
|
||||
if (_initterm_e(__xi_a, __xi_z) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do C++ initialization:
|
||||
_initterm(__xc_a, __xc_z);
|
||||
return true;
|
||||
}
|
||||
|
||||
Of particular interest is the _initterm function, with the following implementation:
|
||||
|
||||
// Calls each function in [first, last). [first, last) must be a valid range of
|
||||
// function pointers. Each function is called, in order.
|
||||
extern "C" void __cdecl _initterm(_PVFV* const first, _PVFV* const last)
|
||||
{
|
||||
for (_PVFV* it = first; it != last; ++it)
|
||||
{
|
||||
if (*it == nullptr)
|
||||
continue;
|
||||
|
||||
(**it)();
|
||||
}
|
||||
}
|
||||
|
||||
(Both code examples taken from UCRT 10.0.14393.0)
|
||||
|
||||
The addresses __xc_a and __xc_z are symbols in the pdb, so we can find the list of these functions.
|
||||
|
||||
Many are not interesting (just allocating class memory), but some odd functions are included as well (see following sections).
|
||||
|
||||
When in doubt on where a function is being executed, consider checking at __xc_a!
|
||||
|
||||
===========================================================
|
||||
|
||||
Debugger detection
|
||||
|
||||
In _initterm initialization routines, the following device names are referenced:
|
||||
|
||||
\\.\SICE
|
||||
\\.\NTICE
|
||||
\\.\SIWVID
|
||||
|
||||
these correspond to the SoftICE kernel-level debugger. It seems to be rather famous for software cracking.
|
||||
|
||||
I have not looked hard into how these strings are used, but they appear to be XORed against some constant data, with the result held in an array somewhere in .data.
|
||||
|
||||
Not like its much of a hindrance anyway, since we have x64dbg :P
|
||||
|
||||
===========================================================
|
||||
|
||||
EnterObfuscatedMode
|
||||
|
||||
This function is also called from _initterm, and is always called from an obfuscated jump block.
|
||||
|
||||
The first steps are to perform a binary search within the block of data specified by the symbol WARBIRD::g_ObfuscatedBlockData.
|
||||
|
||||
(Fill in later)
|
||||
|
||||
Lastly, the return is called, and the function returns to the decrypted code.
|
|
@ -0,0 +1,24 @@
|
|||
EnterObfuscatedMode notes
|
||||
|
||||
Stack:
|
||||
A8 ebp
|
||||
++ AC to all below
|
||||
00 ecx
|
||||
04 edi
|
||||
08 ebx
|
||||
0C eax / old stub (120F957)
|
||||
10 esi / old stub offset (01001400)
|
||||
14 edx
|
||||
18 GetLastError()
|
||||
1C EFLAGS
|
||||
20 RetAddr
|
||||
24 OldRetAddr (_initterm)
|
||||
|
||||
;; not fastcall calling convention!
|
||||
ecx <- [esp+1C] // Right below RetAddr
|
||||
edx <- STUB_FRAME (??)
|
||||
|
||||
val_3 -> {???}{7 bits select offset for something}{12 bits size decrypted data}
|
||||
offset_1 -> key1
|
||||
offset_2 -> {byte1:last_bit = skip_verify_offset_1}{verify_byte}{key2 as word}
|
||||
offset_3 -> some addr?
|
|
@ -0,0 +1,63 @@
|
|||
#include <std/io.pat>
|
||||
|
||||
struct ObfBlockData {
|
||||
u32 u0;
|
||||
u32 u1;
|
||||
u32 u2;
|
||||
u32 u3;
|
||||
u32 u4;
|
||||
};
|
||||
|
||||
ObfBlockData entries[0x323B] @ 0;
|
||||
|
||||
fn main() {
|
||||
u32 first = 0;
|
||||
u32 first_prev = 0;
|
||||
u32 last = 0x323A;
|
||||
u32 last_prev = 0x323A;
|
||||
u32 sum = 0;
|
||||
u32 stub_ret_offset = 0x20F989;
|
||||
u32 index = 0;
|
||||
u32 xor_value = 0;
|
||||
|
||||
while (true) {
|
||||
index = (first + last) / 2;
|
||||
xor_value = entries[index].u0 ^ sum;
|
||||
|
||||
if (stub_ret_offset >= xor_value) {
|
||||
if (stub_ret_offset >= xor_value + (entries[index].u3 & 0xFFF)) {
|
||||
first = index + 1;
|
||||
last = last_prev;
|
||||
first_prev = first;
|
||||
sum = entries[index].u0 - entries[index].u3;
|
||||
std::print("STAY {0:04X} >= {1:04X}\n", stub_ret_offset, xor_value + (entries[index].u3 & 0xFFF));
|
||||
} else {
|
||||
std::print("BREAK {0:04X} < {1:04X}\n", stub_ret_offset, xor_value + (entries[index].u3 & 0xFFF));
|
||||
std::print("INDEX {}\n", index);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
last = index - 1;
|
||||
last_prev = last;
|
||||
sum = entries[index].u0 + entries[index].u3;
|
||||
}
|
||||
|
||||
if (last < first) {
|
||||
// set_handle_ret(handle_ret_addr);
|
||||
std::print("ERROR\n", xor_value);
|
||||
return;
|
||||
}
|
||||
|
||||
std::print("XOR {0:04X}\n", xor_value);
|
||||
std::print("FIRST {0:04X}\n", first);
|
||||
std::print("LAST {0:04X}\n", last);
|
||||
std::print("SUM {0:04X}\n", sum);
|
||||
}
|
||||
|
||||
u32 val1 = entries[index].u1 + entries[index].u0;
|
||||
u32 val2 = entries[index].u2 - entries[index].u0;
|
||||
u32 val3 = entries[index].u4 + entries[index].u3;
|
||||
std::print("VAL1 {0:04X}\n", val1);
|
||||
std::print("VAL2 {0:04X}\n", val2);
|
||||
std::print("VAL3 {0:04X}\n", val3);
|
||||
};
|
|
@ -0,0 +1,131 @@
|
|||
from qiling import *
|
||||
from qiling.const import *
|
||||
from capstone import *
|
||||
from keystone import *
|
||||
import pefile
|
||||
import json
|
||||
import re
|
||||
import numpy as np
|
||||
|
||||
# Set to binary name
|
||||
BIN_NAME = "sppsvc.exe"
|
||||
|
||||
# Set to function to be analyzed
|
||||
# ANLZ_FUNC = "?VerifyPKeyByInstalledPidConfig@CSLSLicenseManager@@IBEJPAVCSLPKey@@PBGPAUtagPKEY_BASIC_INFO@@PAPAGPAUDECODED_PKEY_DATA@@@Z"
|
||||
ANLZ_FUNC = "_wmain"
|
||||
|
||||
# These magic regexes are derived from the byte markers in notes.txt
|
||||
PUSH_REGEX = rb"(?:\x8dd\$\xfc\x89[\x04\x0c\x14\x1c,4<]\$|[PQRSUVW]){2}\x8d[x\x05\r\x15\x1d-5=].{4}"
|
||||
STUB_RET4_REGEX = rb"\x8b[DLT\\lt\|]\$\x04\xc2\x04\x00"
|
||||
STUB_RET0_REGEX = rb"\x87[\x04\x0c\x14\x1c,4<]\$\xc3"
|
||||
STUB_MAX_SIZE = 0x40 # Maximum size of jump stub
|
||||
|
||||
REG_NAMES = {
|
||||
19: "EAX",
|
||||
20: "EBP",
|
||||
21: "EBX",
|
||||
22: "ECX",
|
||||
23: "EDI",
|
||||
24: "EDX",
|
||||
29: "ESI"
|
||||
}
|
||||
NOP = b"\x90"
|
||||
|
||||
with open("syms.json", "r") as f:
|
||||
sym_data = json.loads(f.read())
|
||||
|
||||
sym_data = {int(a, 16): b for a, b in sym_data.items()}
|
||||
sym_data_inv = {b: a for a, b in sym_data.items()}
|
||||
sym_addrs = sorted(sym_data)
|
||||
|
||||
ks = Ks(KS_ARCH_X86, KS_MODE_32)
|
||||
md = Cs(CS_ARCH_X86, CS_MODE_32)
|
||||
md.detail = True
|
||||
md.skipdata = True
|
||||
ql = Qiling(["./rootfs/sppsvc.exe"], "./rootfs")
|
||||
image_start = ql.loader.images[0].base
|
||||
image_end = ql.loader.images[0].end
|
||||
image_size = image_end - image_start
|
||||
pe = pefile.PE(data=ql.mem.read(image_start, image_size))
|
||||
|
||||
num_obd = ql.unpack(ql.mem.read(sym_data_inv["?g_nNumObfuscatedBlockData@WARBIRD@@3KA"], 4))
|
||||
obd_addr = sym_data_inv["?g_ObfuscatedBlockData@WARBIRD@@3PAU_OBFUSCATED_BLOCK_DATA@1@A"]
|
||||
obd = []
|
||||
|
||||
for i in range(num_obd):
|
||||
obf_block = []
|
||||
|
||||
for j in range(5):
|
||||
obf_block.append(ql.unpack(ql.mem.read(obd_addr + 4*(5*i + j), 4)))
|
||||
|
||||
obd.append(obf_block)
|
||||
|
||||
stub_frame = 0x120f989
|
||||
stub_frame_offset = stub_frame - image_start
|
||||
|
||||
first = 0
|
||||
first_prev = first
|
||||
last = num_obd - 1
|
||||
last_prev = last
|
||||
sum_diff = 0
|
||||
|
||||
while True:
|
||||
index = (first + last) // 2
|
||||
xor_value = obd[index][0] ^ sum_diff
|
||||
|
||||
if stub_frame_offset >= xor_value:
|
||||
if stub_frame_offset >= xor_value + (obd[index][3] & 0xFFF):
|
||||
first = index + 1
|
||||
last = last_prev
|
||||
first_prev = first
|
||||
sum_diff = (obd[index][0] - obd[index][3]) % (1 << 32)
|
||||
else:
|
||||
print(f"XOR {hex(xor_value)} SUMDIFF {hex(sum_diff)} INDEX {hex(index)}")
|
||||
break
|
||||
else:
|
||||
last = index - 1
|
||||
last_prev = last
|
||||
sum_diff = (obd[index][0] + obd[index][3]) % (1 << 32)
|
||||
|
||||
print(f"XOR {hex(xor_value)} SUMDIFF {hex(sum_diff)} INDEX {hex(index)}")
|
||||
|
||||
val1 = (obd[index][1] + obd[index][0]) % (1 << 32)
|
||||
val2 = (obd[index][2] - obd[index][0]) % (1 << 32)
|
||||
val3 = (obd[index][4] + obd[index][3]) % (1 << 32)
|
||||
unk3 = obd[index][3]
|
||||
data_size = unk3 & 0xfff
|
||||
xor_plus_binstart = image_start + xor_value
|
||||
val1_bytes = val1.to_bytes(4, "little")
|
||||
val2_bytes = val2.to_bytes(4, "little")
|
||||
enc_bytes = ql.mem.read(xor_plus_binstart, data_size + 1)
|
||||
dec_bytes = [0] * data_size
|
||||
chksum = 0xa5
|
||||
|
||||
for i in range(data_size - 1, 0, -1):
|
||||
enc_byte = enc_bytes[i]
|
||||
b = enc_bytes[i - 1]
|
||||
|
||||
if i % 2 == 1:
|
||||
if (enc_byte ^ val1_bytes[3]) % 2 == 1:
|
||||
a = (enc_byte ^ val1_bytes[3] ^ val1_bytes[2] ^ 0x100) >> 1
|
||||
else:
|
||||
a = (enc_byte ^ val1_bytes[3]) >> 1
|
||||
|
||||
if (a ^ b) % 2 == 1:
|
||||
dec_byte = (a ^ b ^ val2_bytes[1] ^ 0x100) >> 1
|
||||
else:
|
||||
dec_byte = (a ^ b) >> 1
|
||||
else:
|
||||
if (enc_byte ^ val1_bytes[1]) % 2 == 1:
|
||||
a = (enc_byte ^ val1_bytes[1] ^ val1_bytes[0] ^ 0x100) >> 1
|
||||
else:
|
||||
a = (enc_byte ^ val1_bytes[1]) >> 1
|
||||
|
||||
if (a ^ b) % 2 == 1:
|
||||
dec_byte = (a ^ b ^ val2_bytes[0] ^ 0x100) >> 1
|
||||
else:
|
||||
dec_byte = (a ^ b) >> 1
|
||||
|
||||
chksum ^= dec_byte
|
||||
print(hex(dec_byte))
|
||||
dec_bytes[i] = dec_byte
|
125
peacestone.py
125
peacestone.py
|
@ -2,13 +2,22 @@ from qiling import *
|
|||
from qiling.const import *
|
||||
from capstone import *
|
||||
from keystone import *
|
||||
import pefile
|
||||
import json
|
||||
import re
|
||||
|
||||
# Set to binary name
|
||||
BIN_NAME = "sppsvc.exe"
|
||||
|
||||
# Set to function to be analyzed
|
||||
ANLZ_FUNC = "?VerifyPKeyByInstalledPidConfig@CSLSLicenseManager@@IBEJPAVCSLPKey@@PBGPAUtagPKEY_BASIC_INFO@@PAPAGPAUDECODED_PKEY_DATA@@@Z"
|
||||
# ANLZ_FUNC = "?VerifyPKeyByInstalledPidConfig@CSLSLicenseManager@@IBEJPAVCSLPKey@@PBGPAUtagPKEY_BASIC_INFO@@PAPAGPAUDECODED_PKEY_DATA@@@Z"
|
||||
ANLZ_FUNC = "_wmain"
|
||||
|
||||
# These magic regexes are derived from the byte markers in notes.txt
|
||||
PUSH_REGEX = rb"(?:\x8dd\$\xfc\x89[\x04\x0c\x14\x1c,4<]\$|[PQRSUVW]){2}\x8d[x\x05\r\x15\x1d-5=].{4}"
|
||||
STUB_RET4_REGEX = rb"\x8b[DLT\\lt\|]\$\x04\xc2\x04\x00"
|
||||
STUB_RET0_REGEX = rb"\x87[\x04\x0c\x14\x1c,4<]\$\xc3"
|
||||
STUB_MAX_SIZE = 0x40 # Maximum size of jump stub
|
||||
|
||||
REG_NAMES = {
|
||||
19: "EAX",
|
||||
|
@ -31,7 +40,12 @@ sym_addrs = sorted(sym_data)
|
|||
ks = Ks(KS_ARCH_X86, KS_MODE_32)
|
||||
md = Cs(CS_ARCH_X86, CS_MODE_32)
|
||||
md.detail = True
|
||||
md.skipdata = True
|
||||
ql = Qiling(["./rootfs/sppsvc.exe"], "./rootfs")
|
||||
image_start = ql.loader.images[0].base
|
||||
image_end = ql.loader.images[0].end
|
||||
image_size = image_end - image_start
|
||||
pe = pefile.PE(data=ql.mem.read(image_start, image_size))
|
||||
|
||||
def func_boundary(fun_name):
|
||||
f_start = sym_data_inv[ANLZ_FUNC]
|
||||
|
@ -41,90 +55,117 @@ def func_boundary(fun_name):
|
|||
return f_start, f_end
|
||||
|
||||
def save_patched_exe():
|
||||
for region in ql.mem.get_mapinfo():
|
||||
if region[3] == BIN_NAME:
|
||||
exe_start = region[0]
|
||||
exe_end = region[1]
|
||||
|
||||
print("Fixing up sections...")
|
||||
with open(BIN_NAME.replace(".exe", ".stoned.exe"), "wb") as f:
|
||||
f.write(ql.mem.read(exe_start, exe_end - exe_start))
|
||||
|
||||
def assemble(instrs):
|
||||
return bytes(ks.asm(instrs)[0])
|
||||
|
||||
"""
|
||||
def remove_verify_stubs():
|
||||
global ql
|
||||
"""
|
||||
|
||||
f_start, f_end = func_boundary(ANLZ_FUNC)
|
||||
f_start_orig = f_start
|
||||
orig_ql_state = ql.save()
|
||||
offset = 0
|
||||
|
||||
while f_start < f_end:
|
||||
stop = False
|
||||
f_code = ql.mem.read(f_start, f_end - f_start)
|
||||
instrs = list(md.disasm(f_code, f_start))
|
||||
if __name__ == "__main__":
|
||||
print("peacestone copyleft UMSKT project 2023")
|
||||
print()
|
||||
|
||||
print("INSTRS @ " + hex(f_start))
|
||||
# remove_verify_stubs()
|
||||
# save_patched_exe()
|
||||
|
||||
for i in instrs:
|
||||
print(i)
|
||||
pe_data = ql.mem.read(image_start, image_size)
|
||||
f = open("log.txt", "w")
|
||||
|
||||
for match in re.finditer(STUB_RET4_REGEX, pe_data):
|
||||
match_addr = image_start + match.start()
|
||||
stub_code = ql.mem.read(match_addr - 0x1000, 0x1000)
|
||||
|
||||
try:
|
||||
stub_start_offset = list(re.finditer(PUSH_REGEX, stub_code))[0].start()
|
||||
except:
|
||||
continue
|
||||
|
||||
stub_start_addr = match_addr - 0x1000 + stub_start_offset
|
||||
instrs = list(md.disasm(ql.mem.read(stub_start_addr, 0x47), stub_start_addr))
|
||||
ret = 0
|
||||
for i, inst in enumerate(instrs):
|
||||
if inst.mnemonic == "ret" and inst.op_str == "4":
|
||||
|
||||
for i, instr in enumerate(instrs):
|
||||
print(instr)
|
||||
|
||||
if instr.mnemonic == "ret" and instr.op_str == "4":
|
||||
ret = i
|
||||
break
|
||||
|
||||
if ret < 8:
|
||||
stop = True
|
||||
continue
|
||||
|
||||
# min 7 backwards -> first push instr, then stop
|
||||
# much better than whatever this is supposed to be
|
||||
|
||||
stub_start_index = ret - 8
|
||||
|
||||
if instrs[ret-2].mnemonic == "mov":
|
||||
stub_start_index -= 1
|
||||
|
||||
if instrs[stub_start_index].mnemonic == "mov" or instrs[stub_start_index].mnemonic == "push":
|
||||
stub_start_index = ret - 7
|
||||
stub_start_index += 1
|
||||
elif instrs[stub_start_index].mnemonic != "lea":
|
||||
stop = True
|
||||
print("CANT DEAL WITH THIS")
|
||||
continue
|
||||
|
||||
stub_start = instrs[stub_start_index].address
|
||||
|
||||
try:
|
||||
used_reg = list(md.disasm(instrs[stub_start_index].bytes, 0))[0].operands[0].value.reg
|
||||
except:
|
||||
stop = True
|
||||
raise Exception("CANT DEAL WITH THIS")
|
||||
|
||||
if used_reg not in REG_NAMES:
|
||||
print("CANT DEAL WITH THIS")
|
||||
continue
|
||||
|
||||
used_reg_name = REG_NAMES[used_reg].lower()
|
||||
|
||||
if stop:
|
||||
print("VERIFY STUB REMOVAL FINISHED")
|
||||
break
|
||||
|
||||
print("ADDRESS ASSIGNED @ " + hex(stub_start))
|
||||
|
||||
ql.run(begin=stub_start, end=instrs[stub_start_index+2].address)
|
||||
chksum_data = ql.arch.regs.read(used_reg)
|
||||
|
||||
print("CHKSUM @ " + hex(chksum_data))
|
||||
|
||||
len_stub = (instrs[ret].address + 3) - stub_start
|
||||
ql.mem.write(stub_start, NOP * len_stub)
|
||||
ql.mem.write(chksum_data, NOP * 16)
|
||||
# ql.mem.write(stub_start, NOP * len_stub)
|
||||
# ql.mem.write(chksum_data, NOP * 16)
|
||||
|
||||
push_instrs = list(map(lambda c: bytearray(ks.asm(c)[0]), [f"push {used_reg_name}", f"lea esp, [esp-4]", f"mov [esp], {used_reg_name}"]))
|
||||
jmp_insert_addr = 0
|
||||
|
||||
for inst in instrs[max(0,stub_start_index-4):stub_start_index][::-1]:
|
||||
print(inst)
|
||||
if inst.bytes in push_instrs:
|
||||
ql.mem.write(inst.address, NOP * len(inst.bytes))
|
||||
# ql.mem.write(inst.address, NOP * len(inst.bytes))
|
||||
jmp_insert_addr = inst.address
|
||||
else:
|
||||
break
|
||||
|
||||
f_start = chksum_data + 0x10
|
||||
if jmp_insert_addr == 0:
|
||||
print("CANT DEAL WITH THIS")
|
||||
continue
|
||||
|
||||
print("NOPPED STARTING @ " + hex(jmp_insert_addr))
|
||||
print("NEXT: " + hex(f_start + offset))
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("peacestone copyleft UMSKT project 2023")
|
||||
try:
|
||||
ql.run(begin=jmp_insert_addr, end=instrs[ret].address)
|
||||
|
||||
handler_addr = ql.arch.stack_pop()
|
||||
ql.arch.stack_pop()
|
||||
next_addr = ql.arch.stack_pop()
|
||||
except:
|
||||
handler_addr = -1
|
||||
next_addr = -1
|
||||
|
||||
print("HANDLER @ " + hex(handler_addr))
|
||||
print("JUMP TARGET @ " + hex(next_addr))
|
||||
print(ql.arch.regs.esp)
|
||||
|
||||
f.write(f"J R4 S {hex(jmp_insert_addr)} H {hex(handler_addr)} N {hex(next_addr)}\n")
|
||||
|
||||
# input()
|
||||
print()
|
||||
|
||||
remove_verify_stubs()
|
||||
save_patched_exe()
|
Loading…
Reference in New Issue