Again - can't change global variable in C - c

I'm newbie to C, and this question could be asked for 100 times, but I can't find the same case.
Here's the code:
int r;
void set_idt() {
r = 0x88;
if(r == 0){
kprint_hex_byte(0xff);
}
}
It's strange, but I can't modify the global variable and kprint_hex_byte gets executed. When I try to pick &r inside set_idt() I get the valid address, but assignment of the variable doesn't work!
UPDATE
I decided to provide a minimal example
Here's the minified code:
int r = 0x34def;
void main(){
r = 0x33;
char d = 0;
if(r == 0){
d = 1;
}
else{
d = 2;
}
}
I try to compile it and disassemble it using the following commands:
gcc -ffreestanding -fno-asynchronous-unwind-tables -fno-pie -m32 -c kernel.c -o kernel.o
ld -o kernel.bin -m elf_i386 --oformat binary kernel.o
ndisasm -b 32 kernel.bin > kernel.dis
So as a result of this operations I don't have any hint that any variable r or address space is initialized as 0x34def.
Here's the .dis code:
00000000 55 push ebp
00000001 89E5 mov ebp,esp
00000003 83EC10 sub esp,byte +0x10
00000006 C7052C9004083300 mov dword [dword 0x804902c],0x33
-0000
00000010 C645FF00 mov byte [ebp-0x1],0x0
00000014 A12C900408 mov eax,[0x804902c]
00000019 85C0 test eax,eax
0000001B 7506 jnz 0x23
0000001D C645FF01 mov byte [ebp-0x1],0x1
00000021 EB04 jmp short 0x27
00000023 C645FF02 mov byte [ebp-0x1],0x2
00000027 90 nop
00000028 C9 leave
00000029 C3 ret
PS
In the original example when I tried to disassemble it, I also had some assembler instructions dealing with expected memory address and commands test and jnz were presented the exact same way, but it didn't work as expected

Related

GDB showing wrong address to local variables

The below code is an snippet from the 2nd stage loader program. It is running in Real Mode and gets called by the bootloader program. The problem is that GDB is showing wrong addresses to variables allocated in stack.
|------|------|------|
|Name |GDB |Actual|
|------|------|------|
|char a|0x7be7|0x7bfb|
|char b|0x7be6|0x7bfa|
|------|------|------|
Source:
__attribute__((noreturn))
void __main()
{
char a = 'A';
char b = 'B';
while(1);
}
Disassembly:
00008000 <__main>:
8000: 66 55 push ebp
8002: 66 89 e5 mov ebp,esp
8005: 66 83 ec 10 sub esp,0x10
8009: 67 c6 45 ff 41 mov BYTE PTR [ebp-0x1],0x41 <--- char a
800e: 67 c6 45 fe 42 mov BYTE PTR [ebp-0x2],0x42 <--- char b
8013: eb fe jmp 8013 <__main+0x13>
This file gets loaded at physical location 0x8000 by a custom bootloader.
QEMU and GDB
> qemu-system-i386 -fda build/boot.flp -s -S
> gdb loader.sym
target remote localhost:1234
set architecture i386
b __main
c
s
s
p &a
0x7be7 "" <-- Not EBP - 1
p &b
0x7be6 "" <-- Not EBP - 2
info reg
eax 0x0 0
ecx 0x0 0
edx 0x7de3 32227
ebx 0x8000 32768
esp 0x7bec 0x7bec
ebp 0x7bfc 0x7bfc <-- char a is at 0x7bfb and char b is at 0x7bfa
esi 0x0 0
edi 0x0 0
eip 0x8013 0x8013 <__main+19>
eflags 0x202 [ IF ]
cs 0x0 0
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
I do not really understand what is going on. Could it be the -m16 option?
Compilation
gcc -std=c99 \
-nostartfiles \
-c \
-g \
-ffreestanding \
-fno-pie \
-fno-stack-protector \
-m16 \
-march=i386 \
-Wpedantic \
-Wextra \
-Wall \
-O0 bootloader/x86/phase2/loader.c -o $TEMPDIR/loader.o || exit
ld -m elf_i386 --nmagic --script=build/loader.ld $TEMPDIR/loader.o -o $TEMPDIR/loader.lo || exit
objcopy --only-keep-debug $TEMPDIR/loader.lo $SYMDIR/loader.sym||exit
objcopy -O binary $TEMPDIR/loader.lo $OBJDIR/LOADER.flt||exit
Linker Script (build/loader.ld)
ENTRY (__main)
SECTIONS
{
. = 0x8000; /* Loader is loaded at 0x0000:0x8000 */
.text :AT(0x0)
{
*.o (.text);
}
.data :
{
*.o (.data);
*.o (.bss);
*.o (.rodata);
}
/DISCARD/ :
{
*(.eh_frame)
}
}
Things I tried:
Using -m32 instead of -m16 and .code16gcc at the top of the C file.
Verified that GCC, GDB works perfectly when compilling a native application.
Used --oformat binary option in ld instead of objcopy
PS:
GCC Version: 8.3.0
GNU ld Version: 2.31.1
Linux Debian 10

Remove stack frame setup/initilization

I have the following program:
void main1() {
((void(*)(void)) (0xabcdefabcdef)) ();
}
I create it with the following commands:
clang -fno-stack-protector -c -static -nostdlib -fpic -fpie -O0 -fno-asynchronous-unwind-tables main.c -o shellcode.o
ld shellcode.o -o shellcode -S -static -dylib -e main1 -order_file order.txt
gobjcopy -O binary --only-section=.text shellcode shellcode.output
The assembly looks like the following:
//
// ram
// ram: 00000000-00000011
//
**************************************************************
* FUNCTION *
**************************************************************
undefined FUN_00000000()
undefined AL:1 <RETURN>
FUN_00000000
00000000 55 PUSH RBP
00000001 48 89 e5 MOV RBP,RSP
00000004 48 b8 ef MOV RAX,0xabcdefabcdef
cd ab ef
cd ab 00 00
0000000e ff d0 CALL RAX
00000010 5d POP RBP
00000011 c3 RET
How do I get clang to remove the PUSH RBP, MOV RBP,RSP and POP RBP instructions as they are unnecessary?
I can do this if I write the program in assembly with the following lines:
.globl start
start:
movq $0xabcdefabcdef, %rax
call *%rax
ret
and with the following build commands:
clang -static -nostdlib main.S -o crashme.o
gobjcopy -O binary --only-section=.text crashme.o crashme.output
and the resulting assembly:
//
// ram
// ram: 00000000-0000000c
//
assume DF = 0x0 (Default)
00000000 48 b8 ef MOV RAX,0xabcdefabcdef
cd ab ef
cd ab 00 00
0000000a ff d0 CALL RAX
0000000c c3 RET
but I would much rather write C code instead of assembly.
You forgot to enable optimization. Any optimization level like -O3 enables -fomit-frame-pointer.
It will also optimize the tailcall into a jmp instead of call/ret though. If you need to avoid that for some reason, maybe you can use -fomit-frame-pointer at the default -O0.
For shellcode you might want -Os to optimize for code size. Or even clang's -Oz; that will have a side-effect of avoiding some 0 bytes in the machine code by using push imm8 / pop reg to put small constants in registers, instead of mov reg, imm32.

GCC - relative addressing on Call statement falls short

I'm new to GCC development, so I'm having a problem with a simple C program using an i686 cross compiler to output a flat binary file.
Here's the C program,
void printChar(void);
void main() {
printChar();
L1:
goto L1;
}
void printChar(void)
{
__asm__ (
"movb $62, %al\n\t" // '>'
"mov $0x0e, %ah \n\t" // video function 0Eh (print char)
"mov $0x0007, %ebx \n\t" // color
"int $0x10\n\t"
);
}
here's the script file commands,
i686-elf-gcc -c test.c -o test.o -ffreestanding -Wall -Wextra
i686-elf-ld test.o -o test.bin --oformat binary --entry main
here's the debug listing,
0100 55 PUSH BP
0101 89E5 MOV BP,SP
0103 83E4F0 AND SP,-10
0106 E80200 CALL 010B
0109 0000 ADD [BX+SI],AL
010B EBFE JMP 010B
010D 55 PUSH BP
010E 89E5 MOV BP,SP
0110 B03E MOV AL,3E
0112 B40E MOV AH,0E
0114 BB0700 MOV BX,0007
0117 0000 ADD [BX+SI],AL
0119 CD10 INT 10
011B 5D POP BP
011C C3 RET
011D 0000 ADD [BX+SI],AL
011F 0014 ADD [SI],DL
The call statement at 106 is calling an address 2 bytes short (10B) of the address it should be calling (10D).
There's probably some simple alignment directive I should be using somewhere, but I can't find it. Any help is appreciated. Thanks..

gcc/ld script ignores the start adress of the .text section and adds a lot of junk to my binary

I am trying to build the following really small C program into a raw binary file:
asm ("call sys_main\n" // Immediately run sys_main at start of code
"__asm_loop_halt:\n"
"jmp __asm_loop_halt\n"); // Then halt
int sys_main() {
short *addr = (short*) 0x08b000; // Address start of EGA-VRAM
*addr = 0x0f41; // Write white 'A' on black to screen
}
Because I am trying to create a raw binary I have to use a linker script gcc -std=gnu99 -Os -nostdlib -m32 -march=i386 -ffreestanding -Wl,--nmagic,--script=386.ld -o test test.c:
OUTPUT_FORMAT(binary)
SECTIONS
{
.text 0x0500 :
{
*(.text);
}
.data :
{
*(.data);
*(.bss);
*(.rodata);
}
_heap = ALIGN(4);
}
The script is supposed to tell the linker that the code starts running at 0x500 and that it should only create a binary file. However when I disassemble the binary, I get:
00000000 E802000000 call dword 0x7
00000005 EBFE jmp short 0x5
00000007 55 push ebp
00000008 89E5 mov ebp,esp
0000000A 66C70500B0080041 mov word [dword 0x8b000],0xf41
-0F
00000013 5D pop ebp
00000014 C3 ret
00000015 0000 add [eax],al
00000017 001400 add [eax+eax],dl
......
Appearantly the linker still took 0x0 as the start address of the code and also added a bunch of random data behind the last senseful 'ret' instruction, that is in total 4 times as big as the code.
What is this data, why is it there and what did I do wrong to have my code start at 0x0?
Edit: Thanks to Eugene's tip with the map I discovered that the bytes behind the .text section are .eh_frame responsible for exception handling which can easily removed by calling gcc with -fno-asynchronous-unwind-tables.

Linux Shellcode "Hello, World!"

I have the following working NASM code:
global _start
section .text
_start:
mov eax, 0x4
mov ebx, 0x1
mov ecx, message
mov edx, 0xF
int 0x80
mov eax, 0x1
mov ebx, 0x0
int 0x80
section .data
message: db "Hello, World!", 0dh, 0ah
which prints "Hello, World!\n" to the screen. I also have the following C wrapper which contains the previous NASM object code:
char code[] =
"\xb8\x04\x00\x00\x00"
"\xbb\x01\x00\x00\x00"
"\xb9\x00\x00\x00\x00"
"\xba\x0f\x00\x00\x00"
"\xcd\x80\xb8\x01\x00"
"\x00\x00\xbb\x00\x00"
"\x00\x00\xcd\x80";
int main(void)
{
(*(void(*)())code)();
}
However when I run the code, it seems like the assembler code isn't executed, but the program exits fine. Any ideas?
Thanks
When you inject this shellcode, you don't know what is at message:
mov ecx, message
in the injected process, it can be anything but it will not be "Hello world!\r\n" since it is in the data section while you are dumping only the text section. You can see that your shellcode doesn't have "Hello world!\r\n":
"\xb8\x04\x00\x00\x00"
"\xbb\x01\x00\x00\x00"
"\xb9\x00\x00\x00\x00"
"\xba\x0f\x00\x00\x00"
"\xcd\x80\xb8\x01\x00"
"\x00\x00\xbb\x00\x00"
"\x00\x00\xcd\x80";
This is common problem in shellcode development, the way to work around it is this way:
global _start
section .text
_start:
jmp MESSAGE ; 1) lets jump to MESSAGE
GOBACK:
mov eax, 0x4
mov ebx, 0x1
pop ecx ; 3) we are poping into `ecx`, now we have the
; address of "Hello, World!\r\n"
mov edx, 0xF
int 0x80
mov eax, 0x1
mov ebx, 0x0
int 0x80
MESSAGE:
call GOBACK ; 2) we are going back, since we used `call`, that means
; the return address, which is in this case the address
; of "Hello, World!\r\n", is pushed into the stack.
db "Hello, World!", 0dh, 0ah
section .data
Now dump the text section:
$ nasm -f elf shellcode.asm
$ ld shellcode.o -o shellcode
$ ./shellcode
Hello, World!
$ objdump -d shellcode
shellcode: file format elf32-i386
Disassembly of section .text:
08048060 <_start>:
8048060: e9 1e 00 00 00 jmp 8048083 <MESSAGE>
08048065 <GOBACK>:
8048065: b8 04 00 00 00 mov $0x4,%eax
804806a: bb 01 00 00 00 mov $0x1,%ebx
804806f: 59 pop %ecx
8048070: ba 0f 00 00 00 mov $0xf,%edx
8048075: cd 80 int $0x80
8048077: b8 01 00 00 00 mov $0x1,%eax
804807c: bb 00 00 00 00 mov $0x0,%ebx
8048081: cd 80 int $0x80
08048083 <MESSAGE>:
8048083: e8 dd ff ff ff call 8048065 <GOBACK>
8048088: 48 dec %eax <-+
8048089: 65 gs |
804808a: 6c insb (%dx),%es:(%edi) |
804808b: 6c insb (%dx),%es:(%edi) |
804808c: 6f outsl %ds:(%esi),(%dx) |
804808d: 2c 20 sub $0x20,%al |
804808f: 57 push %edi |
8048090: 6f outsl %ds:(%esi),(%dx) |
8048091: 72 6c jb 80480ff <MESSAGE+0x7c> |
8048093: 64 fs |
8048094: 21 .byte 0x21 |
8048095: 0d .byte 0xd |
8048096: 0a .byte 0xa <-+
$
The lines I marked are our "Hello, World!\r\n" string:
$ printf "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x21\x0d\x0a"
Hello, World!
$
So our C wrapper will be:
char code[] =
"\xe9\x1e\x00\x00\x00" // jmp (relative) <MESSAGE>
"\xb8\x04\x00\x00\x00" // mov $0x4,%eax
"\xbb\x01\x00\x00\x00" // mov $0x1,%ebx
"\x59" // pop %ecx
"\xba\x0f\x00\x00\x00" // mov $0xf,%edx
"\xcd\x80" // int $0x80
"\xb8\x01\x00\x00\x00" // mov $0x1,%eax
"\xbb\x00\x00\x00\x00" // mov $0x0,%ebx
"\xcd\x80" // int $0x80
"\xe8\xdd\xff\xff\xff" // call (relative) <GOBACK>
"Hello wolrd!\r\n"; // OR "\x48\x65\x6c\x6c\x6f\x2c\x20\x57"
// "\x6f\x72\x6c\x64\x21\x0d\x0a"
int main(int argc, char **argv)
{
(*(void(*)())code)();
return 0;
}
Lets test it, using -z execstack to enable read-implies-exec (process-wide, despite "stack" in the name) so we can executed code in the .data or .rodata sections:
$ gcc -m32 test.c -z execstack -o test
$ ./test
Hello wolrd!
It works. (-m32 is necessary, too, on 64-bit systems. The int $0x80 32-bit ABI doesn't work with 64-bit addresses like .rodata in a PIE executable. Also, the machine code was assembled for 32-bit. It happens that the same sequence of bytes would decode to equivalent instructions in 64-bit mode but that's not always the case.)
Modern GNU ld puts .rodata in a separate segment from .text, so it can be non-executable. It used to be sufficient to use const char code[] to put executable code in a page of read-only data. At least for shellcode that doesn't want to modify itself.
As BSH mentioned, your shellcode does not contain the message bytes. Jumping to the MESSAGE label and calling the GOBACK routine just before defining the msg byte was a good move as the address of msg would be on the top of the stack as return address which could be popped to ecx, where the address of msg is stored.
But both yours and BSH's code has a slight limitation.
It contains NULL bytes ( \x00 ) which would be considered as end of string when dereferenced by the function pointer.
There is a smart way around this. The values you store into eax, ebx and edx are small enough to be directly written into the lower nibbles of the respective registers in one go by accessing al, bl and dl respectively.
The upper nibble may contain junk value so it can be xored.
b8 04 00 00 00 ------ mov $0x4,%eax
becomes
b0 04 ------ mov $0x4,%al
31 c0 ------ xor %eax,%eax
Unlike the prior instruction set, the new instruction set does not contain any NULL byte.
So, the final program looks like this :
global _start
section .text
_start:
jmp message
proc:
xor eax, eax
mov al, 0x04
xor ebx, ebx
mov bl, 0x01
pop ecx
xor edx, edx
mov dl, 0x16
int 0x80
xor eax, eax
mov al, 0x01
xor ebx, ebx
mov bl, 0x01 ; return 1
int 0x80
message:
call proc
msg db " y0u sp34k 1337 ? "
section .data
Assembling and linking :
$ nasm -f elf hello.asm -o hello.o
$ ld -s -m elf_i386 hello.o -o hello
$ ./hello
y0u sp34k 1337 ? $
Now extract the shellcode from the hello binary :
$ for i in `objdump -d hello | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\\x$i" ; done
output:
\xeb\x19\x31\xc0\xb0\x04\x31\xdb\xb3\x01\x59\x31\xd2\xb2\x12\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xb3\x01\xcd\x80\xe8\xe2\xff\xff\xff\x20\x79\x30\x75\x20\x73\x70\x33\x34\x6b\x20\x31\x33\x33\x37\x20\x3f\x20
Now we can have our driver program to launch the shellcode.
#include <stdio.h>
char shellcode[] = "\xeb\x19\x31\xc0\xb0\x04\x31\xdb"
"\xb3\x01\x59\x31\xd2\xb2\x12\xcd"
"\x80\x31\xc0\xb0\x01\x31\xdb\xb3"
"\x01\xcd\x80\xe8\xe2\xff\xff\xff"
"\x20\x79\x30\x75\x20\x73\x70\x33"
"\x34\x6b\x20\x31\x33\x33\x37\x20"
"\x3f\x20";
int main(int argc, char **argv) {
(*(void(*)())shellcode)();
return 0;
}
There are certain security features in modern compilers like NX protection which prevents execution of code in data segment or stack. So we should explicitly specify the compiler to disable these.
$ gcc -g -Wall -fno-stack-protector -z execstack launcher.c -o launcher
Now the launcher can be invoked to launch the shellcode.
$ ./launcher
y0u sp34k 1337 ? $
For more complex shellcodes, there would be another hurdle. Modern Linux kernels have ASLR or Address Space Layout Randomization
You may need to disable this before your inject the shellcode, especially when it is through buffer overflows.
root#localhost:~# echo 0 > /proc/sys/kernel/randomize_va_space

Resources