Linux syscall table from C re-written to assembly - linux

So, from this code, a kernel module, there is a get_system_call function to get the x86_64 system call table.
#define IA32_LSTAR 0xc0000082
void *get_system_call(void)
{
void *system_call;
unsigned char *ptr;
int i, low, high;
asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (IA32_LSTAR));
system_call = (void*)(((long)high<<32) | low);
printk(KERN_INFO "system_call: 0x%p\n", system_call);
for (ptr=system_call, i=0; i<500; i++) {
if (ptr[0] == 0xff && ptr[1] == 0x14 && ptr[2] == 0xc5)
return (void*)(0xffffffff00000000 | *((unsigned int*)(ptr+3)));
ptr++;
}
return NULL;
}
I try to rewrite the x86 assembly version like this:
global _start
section .text
_start:
mov ecx, 0xc0000082
rdmsr
mov edx, 32
mov ecx, edx
sal edx, cl
or eax, edx
.loop_init:
mov ecx, eax
add ecx, 500
jmp .loop_body
.loop:
add eax, 1
cmp ecx, eax
je .fail
.loop_body:
cmp byte [eax], 0xff
jne .loop
cmp byte [eax+1], 0x14
jne .loop
cmp byte [eax+2], 0xc5
jne .loop
.success:
mov ecx, 0xffffffff
mov eax, dword [eax+3]
or eax, ecx
ret
.fail:
xor eax, eax
ret
My question is: Is that correct or I'm totally wrong ?

Related

How to find characters in a string Assembly x86?

I'm trying to rewrite the C code below in Assembly x86
int myFn( char * v, char c, int size ) {
int i;
for(i=0; i < size; i++ )
if( v[i] == c )
return i;
return -1;
}
I've tried to use this code in x86:
myFn:
mov esi, 0
mov ebx, [esp + 8]
mov ecx, [esp + 12]
FOR:
mov eax, -1
cmp esi, [esp + 4]
jge ENDFOR
cmp [ecx + esi], ebx
je EQUAL
inc esi
jmp FOR
EQUAL:
mov eax, [esi]
ENDFOR:
ret
I've also created this program to test the function:
section .data
fmt: db "strfind: %d", 10, 0
str: db "test", 0
section .text
global main
extern printf
main:
mov eax, 's'
mov ebx, 4
push str
push eax
push ebx
call myFn
add esp, 12
push eax
push fmt
call printf
add esp, 8
ret
myFn:
mov esi, 0
mov ebx, [esp + 8]
mov ecx, [esp + 12]
FOR:
mov eax, -1
cmp esi, [esp + 4]
jge ENDFOR
cmp [ecx + esi], ebx
je EQUAL
inc esi
jmp FOR
EQUAL:
mov eax, [esi]
ENDFOR:
ret
I'm getting Segmentation Fault error or the wrong result when trying to test it. I believe the problem is when comparing the character of the string with the character I want to find

Assembly function on strings

I made function which should return the number of the highest sequence of the same character in a string. So in case of string 'aabbbcaaaabbccc' it should be 4, in case of 'aaaaa' it should be 5. So for 'aaaaa' this function should return 5, actually it returns 2. I am staring on it long time, but I can't see a mistake.
unsigned long najdlhsia(const char *vstup) {
__asm {
mov eax, 0
mov ecx, 0
mov ebx, vstup
cmp [ebx], 0
je k
mov edx, [ebx]
add ebx, 1
inc eax
inc ecx
c: cmp byte ptr[ebx], 0
je p
cmp [ebx], edx
jne a1
inc ecx
add ebx, 1
jmp c
a1: cmp ecx, eax
jng a2
mov eax, ecx
a2: mov ecx, 1
mov edx, [ebx]
add ebx, 1
jmp c
p: cmp ecx, eax
jng k
mov eax, ecx
k:
}
}
int main()
{
printf("%d", najdlhsia("aaaaa"));
return 0;
}

IDA PRO Struct Pointer Counter big number not starting from address offset 0, Lowers a bit slightly but not completely to 0

I put the whole question in 3 images from research it seems I need to use CTRL+R but I don't think that's what I need since I could lower the number a bit lower just can't lower it to the proper amount of 0.
I think the problem is I'm not creating the structs properly probably missing something.
ASM Code:
.text:0040E040 ; =============== S U B R O U T I N E =======================================
.text:0040E040
.text:0040E040
.text:0040E040 ; struct_ARENA *__thiscall code(struct_PLAYER *player, const void *buf, unsigned int len, int a4)
.text:0040E040 sub_40E040 proc near
.text:0040E040
.text:0040E040
.text:0040E040 buf = dword ptr 4
.text:0040E040 len = dword ptr 8
.text:0040E040 a4 = dword ptr 0Ch
.text:0040E040
.text:0040E040 push ebx
.text:0040E041 push esi
.text:0040E042 mov esi, ecx
.text:0040E044 mov eax, [esi+1Ch]
.text:0040E047 test eax, eax
.text:0040E049 jz short loc_40E093
.text:0040E04B mov ecx, [eax+0FF0Ch]
.text:0040E051 xor ebx, ebx
.text:0040E053 test ecx, ecx
.text:0040E055 jle short loc_40E093
.text:0040E057 push edi
.text:0040E058 push ebp
.text:0040E059 mov ebp, [esp+10h+a4]
.text:0040E05D mov edi, 0FB20h
.text:0040E062
.text:0040E062 loc_40E062:
.text:0040E062 mov eax, [edi+eax]
.text:0040E065 cmp eax, esi
.text:0040E067 jz short loc_40E082
.text:0040E069 mov ecx, [eax+38h]
.text:0040E06C test ecx, ecx
.text:0040E06E jnz short loc_40E082
.text:0040E070 mov ecx, [esp+10h+len]
.text:0040E074 mov edx, [esp+10h+buf]
.text:0040E078 push ebp ; a4
.text:0040E079 push ecx ; len
.text:0040E07A push edx ; buf
.text:0040E07B mov ecx, eax ; this
.text:0040E07D call SendPlayerReliablePacket
.text:0040E082
.text:0040E082 loc_40E082:
.text:0040E082
.text:0040E082 mov eax, [esi+1Ch]
.text:0040E085 inc ebx
.text:0040E086 add edi, 4
.text:0040E089 cmp ebx, [eax+0FF0Ch]
.text:0040E08F jl short loc_40E062
.text:0040E091 pop ebp
.text:0040E092 pop edi
.text:0040E093
.text:0040E093 loc_40E093:
.text:0040E093
.text:0040E093 pop esi
.text:0040E094 pop ebx
.text:0040E095 retn 0Ch
.text:0040E095 sub_40E040 endp
.text:0040E095 ; ---------------------------------------------------------------------------
.text:0040E098 align 10h
Here is one that looks better only 1 struct instead of 2 but still same problem

nasm, read syscall reads over buffer size

I have the following code. It works ok except one thing which limits its usage in other programs. When I run it in the debugger, Linux read system call returns value always bigger than the specified buffer size. Why is it and how to fix it, because it doesn't let the program to loop through the buffer array without a segmentation fault?
SECTION .data
address dd "log.txt", 0
badf dd "Bad file!",0
buffsize dd 1024
size dd 1024
filedesc dd 0
section .bss
buf resb 1024
SECTION .text
global main
main:
mov ebx, address
mov eax, 5 ; open(
mov ecx, 0 ; read-only mode
int 80h ; );
mov [filedesc], eax
read_loop:
mov ebx, [filedesc] ; file_descriptor,
mov eax, 3 ; read(
mov ecx, buf ; *buf,
mov edx, buffsize ; *bufsize
int 80h ; );
test eax, eax
jz done
js badfile
mov eax, 4 ; write(
mov ebx, 1 ; STDOUT,
mov edx, buffsize
mov ecx, buf ; *buf
int 80h
jmp read_loop
badfile:
mov eax, 4 ; write(
mov ebx, 1 ; STDOUT,
mov edx, 10
mov ecx, badf ; *buf
int 80h
done:
mov eax, 6
mov ebx, [filedesc]
int 0x80
mov ebx,0
mov eax,1
int 0x80
mov edx, buffsize ; *bufsize
Is wrong since buffsize is declared as follows:
buffsize dd 1024
the above code will move the address of buffsize to edx. What you want is:
mov edx, [buffsize]
which will move the value stored at buffsize to edx.
You have a few of those type of errors in there.
Could it be a negative error return code?
I don't see any test in your code for negative values.

strlen in assembly

I made my own implementation of strlen in assembly, but it doesn't return the correct value. It returns the string length + 4. Consequently. I don't see why.. and I hope any of you do...
Assembly source:
section .text
[GLOBAL stringlen:] ; C function
stringlen:
push ebp
mov ebp, esp ; setup the stack frame
mov ecx, [ebp+8]
xor eax, eax ; loop counter
startLoop:
xor edx, edx
mov edx, [ecx+eax]
inc eax
cmp edx, 0x0 ; null byte
jne startLoop
end:
pop ebp
ret
And the main routine:
#include <stdio.h>
extern int stringlen(char *);
int main(void)
{
printf("%d", stringlen("h"));
return 0;
}
Thanks
You are not accessing bytes (characters), but doublewords. So your code is not looking for a single terminating zero, it is looking for 4 consecutive zeroes. Note that won't always return correct value +4, it depends on what the memory after your string contains.
To fix, you should use byte accesses, for example by changing edx to dl.
Thanks for your answers. Under here working code for anyone who has the same problem as me.
section .text
[GLOBAL stringlen:]
stringlen:
push ebp
mov ebp, esp
mov edx, [ebp+8] ; the string
xor eax, eax ; loop counter
jmp if
then:
inc eax
if:
mov cl, [edx+eax]
cmp cl, 0x0
jne then
end:
pop ebp
ret
Not sure about the four, but it seems obvious it will always return the proper length + 1, since eax is always increased, even if the first byte read from the string is zero.
Change the line
mov edx, [ecx+eax]
to
mov dl, byte [ecx+eax]
and
cmp edx, 0x0 ; null byte
to
cmp dl, 0x0 ; null byte
Because you have to compare only byte at a time.
Following is the code. Your original code got off-by-one error. For "h" it will return two h + null character.
section .text
[GLOBAL stringlen:] ; C function
stringlen:
push ebp
mov ebp, esp ; setup the stack frame
mov ecx, [ebp+8]
xor eax, eax ; loop counter
startLoop:
xor dx, dx
mov dl, byte [ecx+eax]
inc eax
cmp dl, 0x0 ; null byte
jne startLoop
end:
pop ebp
ret
More easy way here(ASCII zero terminated string only):
REPE SCAS m8
http://pdos.csail.mit.edu/6.828/2006/readings/i386/REP.htm
I think your inc should be after the jne. I'm not familiar with this assembly, so I don't really know.

Resources