95 Rz-gg
rz-gg stands for rizin egg
, this is the basic block to construct relocatable snippets of code to be used for injection in target processes when doing exploiting.
rz-gg compiles programs written in a simple high-level language into tiny binaries for x86, x86-64, and ARM.
You can also access all the rz-gg commands from the rizin shell. They are present under g
. See g?
for more information about how to use them.
By default, it will compile its own rz-gg
language, but you can also compile C code using GCC or Clang shellcodes depending on the file extension. Let’s create C file called helloworld.c
:
int main() {
(1, "Hello World\n", 13);
writereturn 0;
}
$ rz-gg -a x86 -b32 helloworld.c
e900000000488d3516000000bf01000000b80400000248c7c20d0000000f0531c0c348656c6c6f20576f726c640a00
$ rz-asm -a x86 -b 32 -D e900000000488d3516000000bf01000000b80400000248c7c20d0000000f0531c0c348656c6c6f20576f726c640a00
0x00000000 5 e900000000 jmp 5
0x00000005 1 48 dec eax
0x00000006 6 8d3516000000 lea esi, [0x16]
0x0000000c 5 bf01000000 mov edi, 1
0x00000011 5 b804000002 mov eax, 0x2000004
0x00000016 1 48 dec eax
0x00000017 6 c7c20d000000 mov edx, 0xd
0x0000001d 2 0f05 syscall
0x0000001f 2 31c0 xor eax, eax
0x00000021 1 c3 ret
0x00000022 1 48 dec eax
0x00000023 2 656c insb byte es:[edi], dx
0x00000025 1 6c insb byte es:[edi], dx
0x00000026 1 6f outsd dx, dword [esi]
0x00000027 3 20576f and byte [edi + 0x6f], dl
0x0000002a 2 726c jb 0x98
0x0000002c 3 640a00 or al, byte fs:[eax]
95.1 Compiling rz-gg example
$ cat hello.r
exit@syscall(1);
main@global() {
exit(2);
}
$ rz-gg -a x86 -b 64 hello.r
48c7c00200000050488b3c2448c7c0010000000f054883c408c3
0x00000000 1 48 dec eax
0x00000001 6 c7c002000000 mov eax, 2
0x00000007 1 50 push eax
0x00000008 1 48 dec eax
0x00000009 3 8b3c24 mov edi, dword [esp]
0x0000000c 1 48 dec eax
0x0000000d 6 c7c001000000 mov eax, 1
0x00000013 2 0f05 syscall
0x00000015 1 48 dec eax
0x00000016 3 83c408 add esp, 8
0x00000019 1 c3 ret
$ rz-asm -a x86 -b 64 -D 48c7c00200000050488b3c2448c7c0010000000f054883c408c3
0x00000000 7 48c7c002000000 mov rax, 2
0x00000007 1 50 push rax
0x00000008 4 488b3c24 mov rdi, qword [rsp]
0x0000000c 7 48c7c001000000 mov rax, 1
0x00000013 2 0f05 syscall
0x00000015 4 4883c408 add rsp, 8
0x00000019 1 c3 ret
You can also compile for ARM. For that, specify the architecture as arm
:
$ rz-gg -a arm -b 32 hello.r
00482de90200a0e30c008de508109de50170a0e3000000ef0088bde8
$ rz-asm -a arm -b 32 -D 00482de90200a0e30c008de508109de50170a0e3000000ef0088bde8
0x00000000 4 00482de9 push {fp, lr}
0x00000004 4 0200a0e3 mov r0, 2
0x00000008 4 0c008de5 str r0, [sp, 0xc]
0x0000000c 4 08109de5 ldr r1, [sp, 8]
0x00000010 4 0170a0e3 mov r7, 1
0x00000014 4 000000ef svc 0
0x00000018 4 0088bde8 pop {fp, pc}
95.2 Tiny binaries
You can create tiny binaries for your code using the -F
flag in rz-gg, or the -C
in rz-bin.
.r
$ cat helloworldint main() {
(1, "Hello World\n", 13);
writereturn 0;
}
-gg -O -F helloworld.c
$ rz
./helloworld
$
Hello World
-c < helloworld
$ wc 259
We can see that the size of the binary is just 259 bytes.
95.3 Output format
You can change the output format using the -f
flag. Here’s an example of changing it to python:
$ rz-gg -O -F -f python helloworld.r
$ xxd helloworld | head -n 3
00000000: 696d 706f 7274 2073 7472 7563 740a 6275 import struct.bu
00000010: 6620 3d20 7374 7275 6374 2e70 6163 6b20 f = struct.pack
00000020: 2822 3133 3942 222c 202a 5b0a 3078 3535 ("139B", *[.0x55
You can set the output format to C, PE, ELF, Mach-O, raw, python or javascript.