Saturday, November 3, 2012

How To Convert Assembly Instruction Into Machine Code In Any Type Of Processors Platform

How To Convert Assembly Instruction Into Machine Code In Any Type Of Processors Platform

by cawan (cawan[at]

on 4/11/2012

In windows environment under x86 platform, it is easy to test any assembly instruction
with any debugger such as ollydbg, immunitydbg, or windbg. With ollydbg or immunitydbg,
simply open a dummy .exe file, it will automatically break at the beginning of the code
(_main or TLS, it is up to the debugger setting...). Then, from Code window, drag the
scrollbar to an area which is easy to be recognized, such as full with null instruction
or nop instruction. Click once onto any of that instruction, then press the space bar
once, an assemble window will pop out. So, we can put any assembly instruction there
and let the debugger to convert the assembly instruction into machine code, and replace
the original instruction at the place that we selected previously with our new instruction.
After that, right click on the new instruction, from the popup menu, select "new origin
here", and the EIP will be redirected here. Press F8 to step over the instruction to
observe what has been done by the instruction from register window. This technique is
useful in initial design and verification of shellcode design.

However, this technique is only valid in windows. How about if we want to test and
evaluate some instructions under linux environment when we need to design shellcode for
linux ? Can we use gdb to do the same thing ? A more serious question is, how to test and
evaluate each instruction in RISC processor such as MIPS, ARM, or PPC ? Well, it is simple.
First of all, I personally still have no idea in regarding how to make gdb to assemble
instruction into machine code. If anybody know how to do it, please let me know, thanks.
However, we can use something alternative, the gcc. In gcc, we can put the instruction
that we want to test in a .s file. It is not recommended to use .c file because the
discussion will get a little bit complicated when we need to deal withinline assembly
as well as assembly instruction with c expression operands. Besides, in order to avoid gcc
to find appropriate entry point in linking process, we need -c option to ask gcc to
compile only the .s file into .o object file. Let's do it.

Host:# echo 'movl $0xffff0000,%eax' > cawan.s
Host:# cat cawan.s
movl $0xffff0000,%eax
Host:# gcc -c cawan.s
Host:# ls cawan.o
Host:# objdump -d cawan.o

cawan.o:     file format elf32-i386

Disassembly of section .text:

00000000 <.text>:
   0: b8 00 00 ff ff       mov    $0xffff0000,%eax

Well, we know the machine code of instruction "mov $0xffff0000,%eax" is b80000ffff, and
it is 5 bytes long. Now, how about MIPS platform ? How about if we need to move 0xffffffff
into t0 register ? Before we start, it is important to understand majority of RISC processors
use fixed-length instruction. So, the maximum immediate value that can support is only 16-bit,
and if we need to move 0xffffffff into t0 register, we need 2 instructions to do the job.
Let's do it now. First we move 0xffff into upper 16-bit is t0 register with "lui $t0,0xffff".
Then we use "ori $t0,$t0,0xffff" to move 0xffff into the lower 16-bit of t0 register. We can
change that 2 instruction into machine code now.

Host:# echo 'lui $t0,0xffff' > cawan.s
Host:# ./mips-linux-gnu-gcc -EL -c cawan.s
Host:# ls cawan.o
Host:# file cawan.o
cawan.o: ELF 32-bit LSB relocatable, MIPS, MIPS32 rel2 version 1 (SYSV), not stripped
Host:# ./mips-linux-gnu-obj
mips-linux-gnu-objcopy  mips-linux-gnu-objdump
Host:# ./mips-linux-gnu-objdump -d cawan.o

cawan.o:     file format elf32-tradlittlemips

Disassembly of section .text:

00000000 <.text>:
   0: 3c08ffff lui t0,0xffff

Good, the machine code of "lui $t0,0xffff" is 3c08ffff. Please note that we are using
MIPS cross compiler (mips-linux-gnu-gcc) to compile the .s file instead of the default
gcc in the host machine. The -EL option in MIPS gcc means to compliance little endian
architecture. When the compiled .o object being checked with file command, it shows the
ELF is really for little endian MIPS. Ok, let us try with "ori $t0,$t0,0xffff" now.

Host:# echo 'ori $t0,$t0,0xffff' > cawan.s
Host:# ./mips-linux-gnu-gcc -EL -c cawan.s
Host:# ./mips-linux-gnu-objdump -d cawan.o

cawan.o:     file format elf32-tradlittlemips

Disassembly of section .text:

00000000 <.text>:
   0: 3508ffff ori t0,t0,0xffff

Nice, the machine code of "ori $t0,$t0,0xffff" is 3508ffff. So, we know we can use
3c08ffff following by 3508ffff to change the value of t0 register into 0xffffffff. But
how to run and evaluate it? Of course with gdb. We need to cross compile a gdb to run
in MIPS environment and use it to do our job. The techniques to use in cross compiling
gdb into MIPS platform will be discussed in next paper. Just assume the MIPS gdb is ready
right now, and we can use it to test our machine code now. Simply open a dummy executable
in gdb, set a breakpoint at _main, and run. The execution should stop at the breakpoint.
Then use set command to put those machine code into appropriate memory address, verify it
with x command. If everything ok, then set the program counter to the memory address that
has the machine codes to be tested. From here, use ni command to step over the instructions
one by one. Observe the state by using x command for memory, or info reg command for
registers. Sometimes, it is a little bit annoying to run several steps to convert an
assembly instruction into machine code. So, it is possible to cascade them as a single
command and display the output in a clearer format.

Host:# echo 'lui $t0,0xffff' > temp.s && ./mips-linux-gnu-gcc -EL -c temp.s &&
./mips-linux-gnu-objdump -d temp.o | grep 0: | sed s/.*0://
3c08ffff lui t0,0xffff
Host:# echo 'ori $t0,$t0,0xffff' > temp.s && ./mips-linux-gnu-gcc -EL -c temp.s &&
./mips-linux-gnu-objdump -d temp.o | grep 0: | sed s/.*0://
3508ffff ori t0,t0,0xffff

Besides, regarding to ARM platform, just change the MIPS gcc and objdump into
ARM version, cross compile the gdb, and do the same thing as mentioned. So, it is really
easy to design and test your shellcode in any type of embedded platform.

pdf version:

No comments:

Post a Comment