1
0
mirror of https://github.com/0O0o0oOoO00/Alas.git synced 2026-05-20 02:19:30 +08:00
Files
Alas/blcrack/cracker/Dobby/source/InstructionRelocation/x86/InstructionRelocationX86Shared.cc
2025-11-01 00:23:46 +08:00

219 lines
6.8 KiB
C++

#include "platform_detect_macro.h"
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
#include "dobby/dobby_internal.h"
#include "InstructionRelocation/x86/InstructionRelocationX86.h"
#include "InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.h"
#include "MemoryAllocator/NearMemoryAllocator.h"
using namespace zz::x86;
// x64 jmp absolute address
inline void codegen_x64_jmp_absolute_addr(CodeBufferBase *buffer, addr_t target) {
// jmp *(rip)
buffer->Emit8(0xFF);
buffer->Emit8(0x25); // ModR/M: 00 100 101
buffer->Emit32(0x00);
// .long target
buffer->Emit64(target);
}
// simple impl for ReloLabel
inline void emit_rel32_label(CodeBufferBase *buffer, uint32_t last_offset, addr_t curr_relo_ip, addr_t orig_dst_ip) {
addr_t curr_offset = buffer->GetBufferSize();
uint32_t relo_insn_len = curr_offset + sizeof(uint32_t) - last_offset;
addr_t relo_ip = curr_relo_ip + relo_insn_len;
int32_t new_offset = orig_dst_ip - relo_ip;
buffer->Emit32(new_offset);
}
int GenRelocateSingleX86Insn(addr_t curr_orig_ip, addr_t curr_relo_ip, uint8_t *buffer_cursor, AssemblerBase *assembler,
CodeBufferBase *code_buffer, x86_insn_decode_t &insn, int8_t mode) {
#define __ code_buffer->
int relocated_insn_len = -1;
x86_options_t conf = {0};
conf.mode = mode;
// decode x86/x64 insn
x86_insn_decode(&insn, (uint8_t *)buffer_cursor, &conf);
// x86 ip register == next instruction address
curr_orig_ip = curr_orig_ip + insn.length;
auto last_relo_offset = code_buffer->GetBufferSize();
static auto x86_insn_encode_start = 0;
static auto x86_insn_encoded_len = 0;
auto x86_insn_encode_begin = [&] { x86_insn_encode_start = code_buffer->GetBufferSize(); };
auto x86_insn_encode_end = [&] { x86_insn_encoded_len = code_buffer->GetBufferSize() - x86_insn_encode_start; };
if (insn.primary_opcode >= 0x70 && insn.primary_opcode <= 0x7F) { // jcc rel8
DEBUG_LOG("[x86 relo] %p: jc rel8", buffer_cursor);
int8_t offset = insn.immediate;
addr_t orig_dst_ip = curr_orig_ip + offset;
#if defined(TARGET_ARCH_IA32)
uint8_t opcode = 0x80 | (insn.primary_opcode & 0x0f);
x86_insn_encode_begin();
__ Emit8(0x0F);
__ Emit8(opcode);
emit_rel32_label(code_buffer, x86_insn_encode_start, curr_relo_ip, orig_dst_ip);
#else
// jcc_true stage 1
const uint8_t label_jcc_cond_true_stage2 = 2;
__ Emit8(insn.primary_opcode);
__ Emit8(label_jcc_cond_true_stage2);
// jcc_false
const uint8_t label_cond_false = 6 + 8;
__ Emit8(0xEB);
__ Emit8(label_cond_false);
// jcc_true stage 2, jmp to orig dst
codegen_x64_jmp_absolute_addr(code_buffer, orig_dst_ip);
#endif
} else if (mode == 64 && (insn.flags & X86_INSN_DECODE_FLAG_IP_RELATIVE) &&
(insn.operands[1].mem.base == RIP)) { // RIP
DEBUG_LOG("[x86 relo] %p: rip", buffer_cursor);
int32_t orig_disp = insn.operands[1].mem.disp;
addr_t orig_dst_ip = curr_orig_ip + orig_disp;
addr_t rip_insn_seq_addr = 0;
{
uint32_t jmp_near_range = (uint32_t)2 * 1024 * 1024 * 1024;
auto rip_insn_seq = (addr_t)NearMemoryAllocator::SharedAllocator()->allocateNearExecMemory(
insn.length + 6 + 8, orig_dst_ip, jmp_near_range);
rip_insn_seq_addr = rip_insn_seq;
}
// jmp *(rip) => jmp to [rip insn seq]
x86_insn_encode_begin();
__ Emit8(0xFF);
__ Emit8(0x25); // ModR/M: 00 100 101
__ Emit32(0);
__ Emit64(rip_insn_seq_addr);
x86_insn_encode_end();
{
auto rip_insn_seq_buffer = CodeBufferBase();
#define ___ rip_insn_seq_buffer.
auto rip_insn_req_ip = rip_insn_seq_addr;
rip_insn_req_ip = rip_insn_req_ip + insn.length; // next insn addr
int32_t new_disp = (int32_t)(orig_dst_ip - rip_insn_req_ip);
// keep orig insn opcode
___ EmitBuffer(buffer_cursor, insn.displacement_offset);
___ Emit32(new_disp);
// keep orig insn immediate
if (insn.immediate_offset) {
___ EmitBuffer((buffer_cursor + insn.immediate_offset), insn.length - insn.immediate_offset);
}
// jmp *(rip) => back to relo process
auto relo_next_ip = curr_relo_ip + x86_insn_encoded_len;
codegen_x64_jmp_absolute_addr(&rip_insn_seq_buffer, relo_next_ip);
DobbyCodePatch((void *)rip_insn_seq_addr, rip_insn_seq_buffer.GetBuffer(), rip_insn_seq_buffer.GetBufferSize());
}
} else if (insn.primary_opcode == 0xEB) { // jmp rel8
DEBUG_LOG("[x86 relo] %p: jmp rel8", buffer_cursor);
int8_t offset = insn.immediate;
addr_t orig_dst_ip = curr_orig_ip + offset;
#if defined(TARGET_ARCH_IA32)
x86_insn_encode_begin();
__ Emit8(0xE9);
emit_rel32_label(code_buffer, x86_insn_encode_start, curr_relo_ip, orig_dst_ip);
#else
// jmp *(rip)
codegen_x64_jmp_absolute_addr(code_buffer, orig_dst_ip);
#endif
} else if (insn.primary_opcode == 0xE8 || insn.primary_opcode == 0xE9) { // call or jmp rel32
DEBUG_LOG("[x86 relo] %p:jmp or call rel32", buffer_cursor);
int32_t offset = insn.immediate;
addr_t orig_dst_ip = curr_orig_ip + offset;
assert(insn.immediate_offset == 1);
#if defined(TARGET_ARCH_IA32)
x86_insn_encode_begin();
__ EmitBuffer(buffer_cursor, insn.immediate_offset);
emit_rel32_label(code_buffer, x86_insn_encode_start, curr_relo_ip, orig_dst_ip);
#else
__ Emit8(0xFF);
if (insn.primary_opcode == 0xE8) {
// call *(rip + 2)
__ Emit8(0x15); // ModR/M: 00 010 101
__ Emit32(2);
// jmp 8
__ Emit8(0xEB);
__ Emit8(0x08);
// dst
__ Emit64(orig_dst_ip);
} else {
// jmp *(rip)
__ Emit8(0x25); // ModR/M: 00 100 101
__ Emit32(0);
// dst
__ Emit64(orig_dst_ip);
}
#endif
} else if (insn.primary_opcode >= 0xE0 && insn.primary_opcode <= 0xE2) { // LOOPNZ/LOOPZ/LOOP/JECXZ
// LOOP/LOOPcc
UNIMPLEMENTED();
} else if (insn.primary_opcode == 0xE3) {
// JCXZ JCEXZ JCRXZ
UNIMPLEMENTED();
} else {
__ EmitBuffer(buffer_cursor, insn.length);
}
// insn -> relocated insn
{
int relo_offset = code_buffer->GetBufferSize();
int relo_len = relo_offset - last_relo_offset;
DEBUG_LOG("insn -> relocated insn: %d -> %d", insn.length, relo_len);
}
return relocated_insn_len;
}
void GenRelocateCodeX86Shared(void *buffer, CodeMemBlock *origin, CodeMemBlock *relocated, bool branch) {
int expected_relocated_mem_size = 32;
x86_try_again:
if (!relocated->addr) {
auto relocated_mem = MemoryAllocator::SharedAllocator()->allocateExecMemory(expected_relocated_mem_size);
if (relocated_mem == nullptr) {
return;
}
relocated->reset((addr_t)relocated_mem, expected_relocated_mem_size);
}
int ret = GenRelocateCodeFixed(buffer, origin, relocated, branch);
if (ret != 0) {
const int step_size = 16;
expected_relocated_mem_size += step_size;
relocated->reset(0, 0);
goto x86_try_again;
}
}
#endif