Как преобразовать 32-битную встроенную сборку gcc в Linux в 64-битный код? [закрыто]
Я пытаюсь конвертироватьRR0D Rasta Ring 0 Отладчик из 32-битного режима в 64-битный режим (длинный режим) в Linux, используя gcc. Я знаком с 32-битной сборкой x86 (в среде MS-DOS), но я новичок в 64-битной сборке x86 и в программировании на ассемблере Linux в целом.
Этот проект предназначен для производственного использования (мне нужен работающий не исходный отладчик), но я также пытаюсь научиться выполнять преобразование 32-разрядных в 64-разрядные. Если возможно, я пытаюсь найти универсальный способ сделать 32-битное в 64-битное преобразование, которое можно было бы сделать в любой 32-битной программе с использованием регулярных выражений (чтобы его можно было автоматизировать). Мне известно, что никакого общего решения не существует (64-битный код может занимать больше места, чем 32-битный код и т. Д. И потреблять больше стека и т. Д.), Но даже в этом случае автоматически преобразованный код будет служить отправной точкой.
Идея состоит в том, чтобы сохранить 8-битные и 16-битные операнды как есть и заменить 32-битные операнды 64-битными операндами. Этот подход, естественно, потерпит неудачу, еслиpushw %ax; pushw %bx; popl %ecx
заменяется наpushw %ax; pushw %bx; popq %rcx
, но программы с хорошим поведением обычно неpush
два 16-битных операнда, а затемpop
один 32-битный операнд, или они?
Это преобразования пока:
Edit: Fix:pusha
/ pushad
can быть заменены последовательнымиpush
'потому чтоpusha
/ pushad
Команды выдвигают значениеsp
/ esp
before фактический толчокsp
, а такжеpush sp
работает так же в 286+, но по-разному в 8088/8086База данных языка ассемблера, Эта разница не проблема здесь (для кода 386+).pusha
а такжеpushad
Таким образом, может быть заменен последовательнымpush
команды.
Альтернатива похожа наOpenSolaris & APOS;privregs.h
code.
Edit: Исправлено: использовать 64-битную адресацию памяти для всех команд.
pusha
-> push %ax; push %cx; push %dx; push %bx; push %sp; push %bp; push %si; push %di
.
Edit: Fix: A valid alternative (using lea
), note that x86 processors are little-endian: pusha
-> movq %rax, -8(%rsp); lea -8(%rsp), %rax; mov %ax, -10(%rsp); movq -8(%rsp), %rax; movw %cx, -4(%rsp); movw %dx, -6(%rsp); movw %bx, -8(%rsp); movw %bp, -12(%rsp); movw %si, -14(%rsp); movw %di, -16(%rsp); lea -16(%rsp), %rsp
.
pushad
-> push %rax; push %rcx; push %rdx; push %rbx; push %rsp; push %rbp; push %rsi; push %rdi
.
Edit: Fix: A valid alternative (using lea
): pushad
-> movq %rax, -8(%rsp); movq %rcx, -16(%rsp); movq %rdx, -24(%rsp); movq %rbx, -32(%rsp); lea -32(%rsp), %rax; movq %rax, -40(%rsp); movq -8(%rsp), %rax; movq %rbp, -48(%rsp); movq %rsi, -56(%rsp); movq %rdi, -64(%rsp); lea -64(%rsp), %rsp
.
Edit: Fix: popa
and popad
pop the value of sp
/ esp
but discard it (Intel instruction set - popa/popad) . Let's pop
it into bx
/ rbx
.
popa
-> popw %di; popw %si; popw %bp; popw %bx; popw %bx; popw %dx; popw %cx; popw %ax
.
popad
-> popq %rdi; popq %rsi; popq %rbp; popq %rbx; popq %rbx; popq %rdx; popq %rcx; popq %rax
.
pushfd
-> pushfq
.
popfd
-> popfq
.
Edit: push
of segment registers, eg. pushw %ds
-> pushw %ax; pushw %ax; movw %ds, %ax; movw %ax, 2(%rsp); popw %ax
.
Edit: pop
of segment registers, eg. popw %ds
-> pushw %ax; movw 2(%rsp), %ax; movw %ax, %ds; popw %ax
.
Edit: inc %reg16
-> add $1, %reg16
, eg. inc %ax
-> add $1, %ax
.
Edit: dec %reg16
-> sub $1, %reg16
, eg. dec %ax
-> sub $1, %ax
.
Edit: inc %reg32
-> add $1, %reg64
, eg. inc %eax
-> add $1, %rax
.
Edit: dec %reg32
-> sub $1, %reg64
, eg. dec %eax
-> sub $1, %rax
.
Edit: aaa
-> ?
Edit: aad
-> ?
Edit: aam
-> ?
Edit: aas
-> ?
Edit: arpl
-> ?
Edit: bound
-> ?
Edit: daa
-> ?
Edit: das
-> ?
Edit: lahf
-> ?
Edit: sahf
-> ?
Edit Fix: any command with direct operand that does not fit in 32-bit operand size in 64-bit mode, eg. pushl $0xDEADBEEF
-> pushq %rax; pushq %rax; movq $0xDEADBEEF, %rax; movq %rax, 8(%rsp); popq %rax
.
ret
with immediate operand: I think in this case the source code must be backtraced to see the sizes of last push
ed operands, and act accordingly, eg. pushl %eax; ret 4
-> pushq %rax; ret 8
.
Edit:: syscalls: int $0x80
-> pushq %rdi; movq %rbp, %r9; movq %rdi, %r8; movq %rbx, %rdi; xchgq %rcx, %rsi; -- replace %rax value using a substitution list --; syscall; popq %rdi; xchgq %rcx, %rsi
(note: 32-bit syscalls may have more than 6 parameters, 6 in registers and the rest in stack, 64-bit syscalls may never have more than 6 parameters).
Edit: Что еще нужно учитывать? Какие еще преобразования потребуются для преобразования 32-битного кода в 64-битный код (для запуска в длинном режиме)?