metasploit-framework/lib/metasm/doc/core/Ia32.txt

235 lines
6.5 KiB
Plaintext

Ia32
====
The Ia32 architecture, aka *Intel_x86*, is the most advanced among the
architectures implemented in the framework. It is a subclass of the
generic <core/CPU.txt>.
It can handle binary code for the 16 and 32bits modes of the processor.
It is a superclass for the <core/X86_64.txt> object, a distinct processor
that handles 64-bit *long_mode* (aka *x64*, *amd64*, *em64t*)
The CPU `shortname` is `ia32` (`ia32_16` in 16-bit mode, and a `_be` suffix
if bigendian)
Opcodes
-------
The opcodes list can be customized to match that available on a specific
version of the processor. The possibilities are:
* 386_common
* 386
* 387
* 486
* pentium
* p6
* 3dnow
* sse
* sse2
* sse3
* vmx
* sse42
Most opcodes are available in the framework, with the notable exception of:
* most sse2 simd instructions
* the AVX instructions
* amd-specific instructions
The `386_common` family is the subset of 386 instruction that are most
commonly found in standard usermode programs (no `in`/`out`/bcd
arithmetic/far call/etc).
This can be useful when manipulating stuff that in not known to be i386
binary code.
Initialization
--------------
An Ia32 <core/CPU.txt> object can be created using the following code:
Metasm::Ia32.new
The `X86` alias may be used in place of `Ia32`.
The constructor accepts optional arguments to specify the CPU size, the
opcode family, and the endianness of the processor. The arguments can
be given in any order. For exemple,
Metasm::Ia32.new(16, 'pentium', :big)
will create a 16-bit mode cpu, with opcodes up to the 'pentium' CPU family,
in big-endian mode.
The Ia32 initializer has the convenience feature that it will create an
X86_64 instance when given the 64 bit size (e.g. `Ia32.new(64)` returns an
X86_64 instance)
Assembler
---------
The parser handles only Intel-style asm syntax, *e.g.*
some_label:
mov eax, 10h
mov ecx, fs:[eax+16]
push dword ptr fs:[1Ch]
call ecx
test al, al
jnz some_label
ret
fmulp ST(4)
Instruction arguments
#####################
The parser recognizes standard registers, such as
* `eax`
* `ah`
* `mm4` (mmx 64bit register)
* `xmm2` (xmm 128bit register)
* `ST` (current top of the FPU stack)
* `ST(3)` (FPU reg nr.3)
* `cs` (segment register)
* `dr3` (debug register)
* `cr2` (control register)
It also supports inexistant registers, such as
* `cr7`
* `dr4`
* `segr6` (segment register nr.6)
The indirections are called `ModRM`. They take the form:
* `[eax]` (memory pointed by `eax`)
* `byte ptr [eax]` (1-byte memory pointed by `eax`)
* `byte [eax]` (same as previous)
* `fs:[eax]` (offset `eax` from the base of the `fs` segment)
* `[fs:eax]` (same as previous)
The pointer itself can be:
* `[eax]` (any register)
* `[eax+12]` (base + numeric offset)
* `[eax+ebx]` (base + register index)
* `[eax + 4*ebx]` (base + 1,2,4 or 8 * index)
* `[eax + 2*ebx + 42]` (both)
Note that the form base + s*index cannot use `esp` as index with s != 1.
For indirection sizes, the size is taken from the size of other arguments
if it is not specified (eg `mov eax, [42]` will be 4 bytes, and `mov al, [42]`
will be 1). The explicit size specifier can be:
* `byte` (8bits)
* `word` (16)
* `dword` (32)
* `qword` (64)
* `oword` (128)
* `_12bits` (12, arbitrary numbers can be used)
Parser commands
###############
The following commands are recognized in an asm source:
* `.mode`
* `.bits`
They are synonymous, and serve to change the mode of the processor to either
16 or 32bits.
They should be the first instruction in the source, changing the mode during
parsing is not supported. This would change only the mode for the next
instructions to be parsed, and for all instructions (incl. those already parsed
at this point) when encoding, which is likely **not** what you want. See the
`codeXX` prefixes.
Note that changing the CPU size once it was created may have bad side-effects.
For exemple, some preprocessor macros may already have been generated according
to the original size of the CPU and will be incorrect from this point on.
Prefixes
########
The following prefixes are handled:
* `lock`
* `rep`, `repz`, `repnz`, `repe`, `repne`
* `code16`, `code32`
The `repXX` prefixes are for string operations (`movsd` etc), but will be set
for any opcode. Only the last of the family will be encoded.
The `code16` will generate instructions to be run on a CPU in 16bit mode,
independantly of the global CPU mode. For exemple,
code16 mov ax, 42h
will generate `"\xb8\x42\x00"` (no opsz override prefix), and will decode or
run incorrectly on an 32bit CPU.
The encoder also has code to handle `jmp hints` prefixes, but the parser has
no equivalent prefix support.
There is currently no way to specify a segment-override prefix for instruction
not using a ModRM argument. Use a `db 26h` style line.
Suffixes
########
The parser implements a specific feature to allow the differenciation of
otherwise ambiguous opcodes, in the form of instruction suffixes.
By default, the assembler will generate the shortest encoding for a given
instruction. To force encoding of another form you can add a specific
suffix to the instruction. In general, metasm will use e.g. register sizes
when possible to avoid this kind of situations, but with immediate-only
displacement this is necessary.
or.a16 [1234h], eax ; use a 16-bit address
or [bx], eax ; use a 16-bit address (implicit from the bx register)
or eax, 1 ; "\x83\xc8\x01"
or.i8 eax, 1 ; "\x83\xc8\x01" (same, shortest encoding)
or.i eax, 1 ; "\x81\xc8\x01\x00\x00\x00" (constant stored in a 32bit field)
movsd.a16 ; use a 16-byte address-size override prefix (copy dword [si] to [di])
push.i16 42h ; push a 16-bit integer
The suffixes are available as follow:
* if the opcode takes an integer argument that can be encoded as either a 8bits or <cpu size>bits, the `.i` and `.i8` variants are created
* if the opcode takes a memory indirection as argument, or is a string operation (`movsd`, `scasb`, etc) the `.a16` and `.a32` variants are created
* if the opcode takes a single integer argument, a far pointer, or is a return instruction, the `.i16` and `.i32` variants are created
C parser
--------
The Ia32 C parser will initialize the type sizes with the `ilp32` memory
model, which is:
* short = 16bits
* int = 32bits
* long = 32bits
* long long = 64bits
* pointer = 32bits
In 16bit mode, the model is `ilp16`, which may not be correct (the 16bits
compiler has not been tested anyway).
The following macros are defined (in the asm preprocessor too)
* `_M_IX86` = 500
* `_X86_`
* `__i386__`