cat > a.out

No explicit questions like "how do I hack xxx.com" please!
Post Reply
G-Brain
Fame ! Where are the chicks?!
Fame ! Where are the chicks?!
Posts: 467
Joined: 08 Nov 2007, 17:00
16
Location: NL

cat > a.out

Post by G-Brain »

I figured it would be pretty cool to be able to write raw hex / binary, and it turns out that's actually a quite feasible goal. Well, it's fucking crazy, but anyway...

Let's write a basic Linux program:

Code: Select all

write(1,"Test\n",5);
exit(0);
...in assembler:

test.asm

Code: Select all

section .text
        global _start

_start:
        mov     al,     4
        mov     bl,     1
        mov     ecx,    message
        mov     dl,     messageLen
        int     0x80

        mov     al,     1
        mov     bl,     0
        int     0x80

message         db      'Test',0x0a
messageLen      equ     5

Code: Select all

nasm -f elf -o test.o test.asm
ld -s -o test test.o
Basic stuff, right? This is the result in HEX:

Code: Select all

87654321  0011 2233 4455 6677 8899 aabb ccdd eeff 0123456789abcdef                                                                                                                                          
00000000: 7f45 4c46 0101 0100 0000 0000 0000 0000  .ELF............
00000010: 0200 0300 0100 0000 6080 0408 3400 0000  ........`...4...
00000020: b400 0000 0000 0000 3400 2000 0100 2800  ........4. ...(.
00000030: 0400 0300 0100 0000 0000 0000 0080 0408  ................
00000040: 0080 0408 7800 0000 7800 0000 0500 0000  ....x...x.......
00000050: 0010 0000 0000 0000 0000 0000 0000 0000  ................
00000060: b004 b301 b973 8004 08b2 05cd 80b0 01b3  .....s..........
00000070: 00cd 8054 6573 740a 0054 6865 204e 6574  ...Test..The Net
00000080: 7769 6465 2041 7373 656d 626c 6572 2030  wide Assembler 0
00000090: 2e39 382e 3339 0000 2e73 6873 7472 7461  .98.39...shstrta
000000a0: 6200 2e74 6578 7400 2e63 6f6d 6d65 6e74  b..text..comment
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000d0: 0000 0000 0000 0000 0000 0000 0b00 0000  ................
000000e0: 0100 0000 0600 0000 6080 0408 6000 0000  ........`...`...
000000f0: 1800 0000 0000 0000 0000 0000 1000 0000  ................
00000100: 0000 0000 1100 0000 0100 0000 0000 0000  ................
00000110: 0000 0000 7800 0000 1f00 0000 0000 0000  ....x...........
00000120: 0000 0000 0100 0000 0000 0000 0100 0000  ................
00000130: 0300 0000 0000 0000 0000 0000 9700 0000  ................
00000140: 1a00 0000 0000 0000 0000 0000 0100 0000  ................
00000150: 0000 0000                                ....
Wait, what? What is that text doing there? I never asked for any of that shit.

Let's do it right this time:

CONSTRUCTING RAW ELF BINARIES MOTHERFUCKER

elf.asm

Code: Select all

BITS 32
        org     0x08048000

ehdr:           ; Elf32_Ehdr
        db      0x7F, "ELF", 1, 1, 1    ;   e_ident
        times 9 db      0
        dw      2                       ;   e_type
        dw      3                       ;   e_machine
        dd      1                       ;   e_version
        dd      _start                  ;   e_entry
        dd      phdr - $$               ;   e_phoff
        dd      0                       ;   e_shoff
        dd      0                       ;   e_flags
        dw      ehdrsize                ;   e_ehsize
        dw      phdrsize                ;   e_phentsize
        dw      1                       ;   e_phnum
        dw      0                       ;   e_shentsize
        dw      0                       ;   e_shnum
        dw      0                       ;   e_shstrndx

ehdrsize      equ     $ - ehdr

phdr:                           ; Elf32_Phdr
        dd      1               ;   p_type
        dd      0               ;   p_offset
        dd      $$              ;   p_vaddr
        dd      $$              ;   p_paddr
        dd      filesize        ;   p_filesz
        dd      filesize        ;   p_memsz
        dd      5               ;   p_flags
        dd      0x1000          ;   p_align

phdrsize      equ     $ - phdr

_start:
        mov     al,     4
        mov     bl,     1
        mov     ecx,    message
        mov     dl,     messageLen
        int     0x80

        mov     al,     1
        mov     bl,     0
        int     0x80

message         db      'Test',0x0a
messageLen      equ     5
filesize        equ     $ - $$
You can just gaze at the first part, it's still the same program at the bottom.

Assemble with:

Code: Select all

nasm -f bin -o elf elf.asm
Let's see what the HEX looks like:

Code: Select all

87654321  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789abcdef                                                                                                                                          
00000000: 7f45 4c46 0101 0100 0000 0000 0000 0000  .ELF............
00000010: 0200 0300 0100 0000 5480 0408 3400 0000  ........T...4...
00000020: 0000 0000 0000 0000 3400 2000 0100 0000  ........4. .....
00000030: 0000 0000 0100 0000 0000 0000 0080 0408  ................
00000040: 0080 0408 6c00 0000 6c00 0000 0500 0000  ....l...l.......
00000050: 0010 0000 b004 b301 b967 8004 08b2 05cd  .........g......
00000060: 80b0 01b3 00cd 8054 6573 740a            .......Test.
Holy shit! That's actually readable! Well, somewhat, if you have the docs.

The first part is just the ELF header, up to 0x53. Then starts our program (at 0x54):

Code: Select all

b004 b301 b967 8004 08b2 05cd
80b0 01b3 00cd 8054 6573 740a
Reading the Intel Software Developers Manual Volume 2A Appendix A: Opcode map, we discover the following:

b0 means: move immediate byte into the AL register (referring to the next byte, 04)

Code: Select all

b0 04

Code: Select all

mov al, 4
b3 means: move immediate byte into BL register

Code: Select all

b3 01

Code: Select all

mov bl, 1
b9 means: move immediate word or double into the eCX register (referring to 67 80 04 08)

Code: Select all

b9 67 80 04 08

Code: Select all

mov ecx, message
For a while there, I wondered what the hell those last 3 bytes were doing there (67 did make sense, it was the address of my string 'Test',0x0a).

Well, 80 04 08 are the last 3 byes in our ORG, 0x08048000. I don't really know why this is, but I'm sure I'll find out, and I'll update the thread when I do. If you'd want to write() another string, all that would change would be the address, 80 04 08 stays the same.

On with the show...

Code: Select all

b2 05

Code: Select all

mov dl, messageLen
And to top it off... call the kernel!

Code: Select all

cd 80

Code: Select all

int 0x80
Let's repeat that:

Code: Select all

write(1,"Test\n",5);

Code: Select all

mov     al,     4
mov     bl,     1
mov     ecx,    message
mov     dl,     messageLen
int     0x80

Code: Select all

b0 04
b3 01
b9 67 80 04 08
b2 05
cd 80
It makes perfect sense!



Now, for exiting:

Code: Select all

b0 01
b3 00
cd 80

Code: Select all

mov al, 1
mov bl, 0
int 0x80

Code: Select all

exit(0);
And the last part....

Code: Select all

54 65 73 74 0a

Code: Select all

Test\n
Now the whole thing one more time:

Code: Select all

write(1,"Test\n",5);
exit(0);

Code: Select all

mov     al,     4
mov     bl,     1
mov     ecx,    message
mov     dl,     messageLen
int     0x80

mov     al,     1
mov     bl,     0
int     0x80

message         db      'Test',0x0a
messageLen      equ     5

Code: Select all

b0 04
b3 01
b9 67 80 04 08
b2 05
cd 80

b0 01
b3 00
cd 80

54 6573 740a
Now you try and fucking convince me that that was not fucking awesome. All it takes is remembering some opcodes and keeping track of addresses. A child could do it. In fact, I am a child. Fuckin' A.

I'm thinking of turning this into some kind of tutorial. You know, like... better.

Thoughts?

I originally posted this on w4ck1ng, but since that place seems to be kinda inactive lately, I figured I'd post it here too :D

Edit: Conclusion: the suck-o layout is not wide enough :P
I <3 MariaLara more than all of you

MariaLara
suck-o-fied!
suck-o-fied!
Posts: 99
Joined: 27 Feb 2008, 17:00
16
Contact:

Post by MariaLara »

I was just wondering about those trailing bytes in the MOV into word register operand myself.
Good job. It's genius. :D

User avatar
Nerdz
The Architect
The Architect
Posts: 1127
Joined: 15 Jun 2005, 16:00
18
Location: #db_error in: select usr.location from sucko_member where usr.id=63;
Contact:

Post by Nerdz »

That's nice! I've never done x86 asm but only some sparc... Anyway I could figured it out and... nice job.

Next is direct binary without calculator or books :roll:
Give a man a fish, you feed him for one day.
Learn a man to fish, you feed him for life.

G-Brain
Fame ! Where are the chicks?!
Fame ! Where are the chicks?!
Posts: 467
Joined: 08 Nov 2007, 17:00
16
Location: NL

Post by G-Brain »

Thanks :D

I'll turn this into a decent tutorial today.
Nerdz wrote:Next is direct binary without calculator or books :roll:
Oh yeah, well that's easy. Looks like I didn't mention that, I will in the decent tutorial. Basically it's like this:

F
1111

FF
1111 1111

CF
1100 1111

It turns out you can just convert the numbers individually! This makes sense, as hexadecimal is just a sort of shorthand for binary.

So:

Code: Select all

exit(0);

Code: Select all

mov al, 1
mov bl, 0
int 0x80

Code: Select all

b0 01
b3 00
cd 80

Code: Select all

1011 0000 0000 0001
1011 0011 0000 0000
1100 1101 1000 0000
:D

Expect the decent tutorial some time today!
I <3 MariaLara more than all of you

G-Brain
Fame ! Where are the chicks?!
Fame ! Where are the chicks?!
Posts: 467
Joined: 08 Nov 2007, 17:00
16
Location: NL

Post by G-Brain »

Tutorial postponed to tomorrow :roll:
I <3 MariaLara more than all of you

Post Reply