Initialize char[] fails, esi contains wrong value - c

I want to initialize a char array, but during I do this my programm crashes. Here's my code:
void kernelEnteredMsg() {
char str[] = "Kernel successfully entered!";
}
Here's the disassembly:
push ebp
mov ebp,esp
push edi
push esi
push ebx
sub esp,byte +0x30
lea edx,[ebp-0x2d]
mov ebx,0x402000 ; load an address outside my data segment
mov eax,0x1d
mov edi,edx
mov esi,ebx ; move this address to edi
mov ecx,eax
rep movsb ; here the programm crashes
add esp,byte +0x30
pop ebx
pop esi
pop edi
pop ebp
ret
I don't understand why it loads esi with 0x402000. But this seems to cause the error. Can somebody explain what happens here and how to fix it?
PS: "Kernel successful entered!" is at 0x1000 in binary file.
C code:
void kernelEnteredMsg();
void entryPoint() {
kernelEnteredMsg();
}
void kernelEnteredMsg() {
char str[] = "Kernel successfully entered!";
int size = 28;
}
Calling assembly code:
extern _entryPoint
global _main
section .text
_main: ; start of kernel
nop
; setup ds, es, ss and gs
mov ax, 16
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x4000
mov ax, 24
mov gs, ax
mov [gs:0], dword 0x07690748 ; test graphics
call _entryPoint ; enter kernel C code
jmp $

This code does copy the string from the .text section to the local stack, because the char array is not 'const'. This may provide a simple solution if you do not need the string to be modified - just make it const char.
I don't understand why it loads esi with 0x402000.
ESI is the source of the string copy instruction 'rep movsb', EDI is the destination.
The address is constructed by IMAGE_BASE+SECTION (IIRC) in the PE file(assuming it is PE.)
Remember in the file there is a FILE_ALIGN and a SECTION_VIRTUAL_ADDRESS, so a section may be
at position 0x1000 in the file(FILE_ALIGN) and at 0x2000 in memory(VIRTUAL_ADDRESS) resulting in IMAGE_BASE+VIRTUAL_ADDRESS=0x402000.
You can use a PE explorer like CFF Explorer(http://www.ntcore.com/exsuite.php)
to display this(if it's a .bin file it may be unapplicable but it has to have some kind of format)
Another possibility may be a wrong state of the DF-Flag leading to wrong behaviour of the string copy instruction (should not happen, because the compiler should take care of this).
Try inserting
__asm__ ("cld");
before the char str[] or in the __main procedure to set string increment to 'UP'.

Related

Why this little shellcode works in a C program,but not alone?

This shellcode does not work when assembled
Section .text
global _start
_start:
jmp GotoCall
shellcode:
pop edi
xor eax, eax
mov byte [edi + 7], al
lea ebx, [edi]
mov long [edi + 8], ebx
mov long [edi + 12], eax
mov byte al, 0x0b
mov ebx, edi
lea ecx, [edi + 8]
lea edx, [edi + 12]
int 0x80
GotoCall:
Call shellcode
db '/bin/shJAAAAKKKK'
This little shellcode will work in this C program called "Shellcode tester".
#shellcode tester
char shellcode[] = "\xe9\x1a\x00\x00\x00\x5f\x31\xc0\x88\x47\x07\x8d\x1f\x89\x5f\x08\x89\x47\x0c\xb0\x0b\x89\xfb\x8d\x4f\x08\x8d\x57\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x4a\x41\x41\x41\x41\x4b\x4b\x4b\x4b";
int main(int argc, char *argv[])
{
int (*ret)(); /* ret is a function pointer */
ret = (int(*)())shellcode; /* ret points to our shellcode */
/* shellcode is type caste as a function */
(int)(*ret)(); /* execute, as a function, shellcode[] */
exit(0); /* exit() */
}
But, it won't work when i assemble and link it,why exactly?
When i debugged it with GDB the problem was EDI Register in this line, the EDI is pointing exactly to strings that exist in stack, i mean the bytes in ascii.
mov byte [edi + 7], al
This shellcode does work when assembled
Another shellcode that i found is this
Section .text
global _start
_start:
jmp GotoCall
shellcode:
xor eax, eax ;zero out eax
push eax ;push 00000000 on to the stack
push 'n/sh' ;push hex //bin/sh on to the stack
push '//bi'
;at this point the stack contains //bin/sh0x00000000
mov ebx, esp ;this satisfies the requirements for *filename (first argument
of execve)
push eax ;push 00000000 on to the stack
;at this point the stack contains 0x00000000//bin/sh0x00000000
mov edx, esp
push ebx ;ebx contains the memory address of the stack where
//bin/sh0x00000000 is.
mov ecx, esp ;this satisfies the requirements for argv (second argument of
execve)
mov al, 11 ;execve syscall number, 0xb works also.
int 0x80 ;initiate
GotoCall:
Call shellcode
it's funny, because this shellcode program exactly works with "Shellcode Test" program in C when i put the opcodes there and completely work alone too.
Please tell me why the first "shellcode" doesn't work alone and the second one does?
char shellcode[] defines a mutable static array.
db defines storage that is in the .text section of the program. On GNU/Linux, that is not writable; the program text is mapped into pages of virtual memory that are marked read-only.
A fix would be to stick the null byte into the db definition, rather than trying to put it in there at run-time.

Assembly and callstack

I'm trying to get an understanding of assembly but unfortunately I have problems to understand the following C code in assembly:
void test_function(int a, int b, int c, int d) {
int flag;
char buffer[10]
flag = 31337;
buffer[0] = 'A';
}
int main() {
test_fuction(1,2,3,4);
}
The assembly of main() looks like this:
push ebp
mov ebp, esp
sub esp,0x18
and esp,0xffffffff0
mov eax,0x0
sub esp,eax
mov DWORD PTR [esp+12], 0x4
mov DWORD PTR [esp+12], 0x3
mov DWORD PTR [esp+12], 0x2
mov DWORD PTR [esp+12], 0x1
call <test_function>
The assembly for test_function(...) looks like this:
push ebp
mov ebp, esp
sub esp,0x28
mov DWORD PTR [ebp-12], 0x7a69 ;this is 31337 in hexadecimal
mov BYTE PTR [ebp-40], 0x41 ;this is the 'A' in ASCII
leave
ret
What is hard for me to understand is:
and esp,0xffffffff0
mov eax,0x0
sub esp,eax
Why are we operating an and with 0xffffffff0 on esp?
And why do we move a 0 to eax and sub the content of eax from esp?
Second:
Through sub esp,0x28 we are allocating 40 bytes of RAM. Why 40? The integer and the 10 chars of the array are altogether only 14 bytes, aren't they?
And why are we moving 0x7a69 to the position [ebp-12] and not to [ebp]? By operating mov ebp, esp I set ebp to the current ESP. Now ESP is pointing to the end of the stack. The last value I pushed on the stack was the ebp by operating push ebp. So EBP (= esp) points behind the saved ebp. So why couldn't I move 0x7a69 to [ebp] just directly behind the saved EBP?
And why is the 'A' moved to [ebp-40]?
This seems to be some standard compiler-generated assembler.
and esp,0xffffffff0
mov eax,0x0
sub esp,eax
The and will make esp a multiple of 16, i.e. alligns it on 16 bytes. Because the stack grows downward it is essentially a substraction, not an addition.
The next mov and add reserve space for the local variables. in main there are no local variables, so their total is 0x0. Because test_function has local variables, 0x28 is moved to eax and added to esp. Probably the compiler has also alligned this on some multiple. Lastly, [ebp-40] is the location on the reserved stack space the compiler has assigned to buffer.

Assembly retrieving buffer to c function parameter

I'm writing an assembly function that will read from IDE through ports.
I'm calling the parameters through x86 base pointer (EBP).
I debugged my kernel.bin (with gdb and qemu) and I that when I'm calling my recv buffer to print, eax will return values like:36h01h10h
IBM Char Table
My disk.asm is divided by read and write. Is it possible that I'm writing it wrong? Is it legal to move directly [ebp+16] to esi (to write)? If I, on read function, move [ebp+16] directly to edi is wrong? I'm using a register poiting to that address and making edi to point to that register:
In my disk.asm, to read the disk I have this:
sub dx, 7 ;dx = 0x1f0
mov ecx, 256
mov edi, bufferrecv
rep insw
(...)
push ebx
mov ebx, [ebp+16]
mov [ebx], long word bufferrecv
pop ebx
mov esp, ebp
pop ebp
ret
And to write disk:
sub dx, 7 ;dx = 0x1f0
mov ecx, 256
mov esi, [ebp+16]
rep outsw
(...)
I'm declaring those functions this way:
Kernel.c
extern int _readd(int sector_count, int nmrsector, STRING in_msg);
extern int writed(int sector_count, int nmrsector, STRING out_msg);
The STRING type was declared inside my types.h as char*

Mixing C and Assembly

I'm doing a program in assembly to read a disk through ports (0x1f0-0x1f7) and I'm mixing it with c. I have a function in assembly that I will call in my c main funtion. My main function as 1 parameter: sectors to read:
Kernel.c
extern int _readd(int nmrsector);
(...)
int sector = 257;
int error = _readd(sector);
if(error == 0) PrintString("Error"); //It is declared on my screen.h file
disk.asm
global _readd
_readd:
push eax
push ebx
push ecx
push edx
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov ecx, eax
cmp ecx, 256
jg short _fail
jne short _good
_fail:
xor eax, eax
leave
ret
_good:
xor eax, eax
mov eax, 12
leave
ret
It crashes when run it with VirtualBox. Any ideas?
If you save CPU registers when you enter a function, you need to restore them when you are finished. Your PUSHs need to be matched with POPs.
Also, if you use a stack frame to access local variables and parameters, setup the frame (push ebp ; mov ebp, esp) before everything, so you can more easily refer to them. Here [ebp+8] doesn't refer to a parameter, because you alter the stack before setting up the frame.

When replacing keyboard interrupt (Interrupt 9) scanf doesn't appear to accept input [duplicate]

This question already has an answer here:
How to prevent duplicate chars when I press keys on the keyboard
(1 answer)
Closed 4 years ago.
I'm writing the main program in Turbo-C and the functions are in assembly. My code is as follows:
lastc.c:
#include <stdio.h>
#include <dos.h>
#include <string.h>
extern void eliminate_multiple_press(); // save old function adress in 32bit pointer
// setvect , add new function to inturupt 9
extern void uneliminate_multiple_press(); // restore old function to inturupt 9
int main()
{
char *str;
eliminate_multiple_press();
printf("Enter a string:\n");
scanf("%s",str);
printf("the string you entered:\n");
printf("%s\n",str);
uneliminate_multiple_press();
return 0;
}
lasta.asm:
.MODEL LARGE
PUBLIC _eliminate_multiple_press
PUBLIC _uneliminate_multiple_press
.STACK 100H
.DATA
INT9SAVE DD ?
hexa_code db 0
scan_code db 0
.CODE
KEY_HANDLER PROC FAR
PUSH AX
MOV AH,0
int 16h
mov scan_code,ah
mov hexa_code,al
POP AX
iRET
KEY_HANDLER ENDP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_eliminate_multiple_press PROC FAR
PUSH AX
PUSH ES
MOV AX,0
MOV ES,AX
;INT9SAVE = GETVECT(9);
MOV AX,ES:[9*4] ; **ax=c1 hex =193 dec**
MOV WORD PTR INT9SAVE,AX
MOV AX,ES:[9*4+2] **ax=15c7 hex = 5575 dec**
MOV WORD PTR INT9SAVE+2,AX
;SETVECT(9,KEY_HANDLER);
CLI
MOV WORD PTR ES:[9*4],OFFSET KEY_HANDLER ; **ES stays 0**
MOV WORD PTR ES:[9*4+2],SEG KEY_HANDLER ; **ES stays 0**
STI
POP ES
POP AX
RET
_eliminate_multiple_press ENDP
;SETVECT(9,INT9SAVE);
_uneliminate_multiple_press PROC FAR
PUSH ES
PUSH AX
MOV AX,0
MOV ES,AX
CLI
MOV AX,WORD PTR INT9SAVE
MOV ES:[9*4],AX
MOV AX,WORD PTR INT9SAVE+2
MOV ES:[9*4+2],AX
STI
POP AX
POP ES
RET
_uneliminate_multiple_press ENDP
END
I can compile the files without error using this command:
tcc -ml -r- lastc.c lasta.asm
The goal of this code is to eliminate multiple (duplicate) key presses on the keyboard. If I type this sequence of characters:
334ffffghjjjj of my keyboard
The output on the screen should be
34fghj
The Problem
When I run the program lastc.exe it gets stuck at printf("enter a string:\n");. I guess I'm having a problem changing Interrupt 9h interrupt service routine to my new function key_handler
Function key_handler is not complete but at least it should END the function and continue to the end of the code
Why does my program appear to be doing nothing when the scanf is called?
Why are eliminate_multiple_press and uneliminate_multiple_press declared as interrupt handlers? They should be normal functions with a return of RET. They are being called as functions and are not intended as responses to an interrupt.
In your C program then:
extern void eliminate_multiple_press(); // save old function adress in 32bit pointer
// setvect , add new function to inturupt 9
extern void uneliminate_multiple_press(); // restore old function to inturupt 9
And your assembly, RET instead of IRET. And you don't need to save so many registers:
_eliminate_multiple_press PROC FAR
push ES
push AX
MOV AX,0
MOV ES,AX
;INT9SAVE = GETVECT(9);
MOV AX,ES:[9*4] ; **ax=c1 hex =193 dec**
MOV WORD PTR INT9SAVE,AX
MOV AX,ES:[9*4+2] **ax=15c7 hex = 5575 dec**
MOV WORD PTR INT9SAVE+2,AX
;SETVECT(9,KEY_HANDLER);
CLI
MOV WORD PTR ES:[9*4],OFFSET KEY_HANDLER ; **ES stays 0**
MOV WORD PTR ES:[9*4+2],SEG KEY_HANDLER ; **ES stays 0**
STI
POP AX
POP ES
RET
_eliminate_multiple_press ENDP
;SETVECT(9,INT9SAVE);
_uneliminate_multiple_press PROC FAR
PUSH ES
PUSH AX
MOV AX,0
MOV ES,AX
CLI
MOV AX,WORD PTR INT9SAVE
MOV ES:[9*4],AX
MOV AX,WORD PTR INT9SAVE+2
MOV ES:[9*4+2],AX ; Was "[27*4+2]" which is incorrect.
STI
POP AX
POP ES
RET
_uneliminate_multiple_press ENDP
An End Of Interrupt (EOI) is a signal sent to a Programmable Interrupt Controller (PIC) to
indicate the completion of interrupt processing for a given interrupt.
mov al,020h ; =EOI
out 020h,al

Resources