GCC inline assembly as binary array - c

Is there any way in GCC to represent inline __asm__ as char[] array? I want to have something like:
void my_func();
char my_code[] = {
__asm__("callq %0" :: "r" (my_func))
};
Later my_code will be used as run-time patch, i.e.
void another_function();
mprotect(another_function, getpagesize(), PROT_WRITE | PROT_READ | PROT_EXEC);
memcpy(another_function + offset, my_code, sizeof(my_code));
Any ideas?

You can just define a function, compile it, then get it's source machine code?
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
void my_func(void) {}
extern void my_code(void);
extern void my_code_end(void);
__attribute__((__used__)) static void _my_code(void) {
asm volatile(
".globl my_code\n"
"my_code:\n"
" callq *%0\n"
" nop\n"
" ret\n"
".globl my_code_end\n"
"my_code_end:\n"
:: "r" (my_func)
);
}
int main() {
size_t my_code_len = (uintptr_t)my_code_end - (uintptr_t)my_code;
const unsigned char *arr = (const char*)my_code;
printf("my_code[%zu]=", my_code_len);
for (size_t i = 0; i < my_code_len; ++i) {
printf("%02x", arr[i]);
}
printf("\n");
return 0;
}
Example output:
my_code[4]=ffd090c3
We can check it's ok from the assembly output:
$ objdump -D ./a.out
...
0000000000000727 <my_code>:
727: ff d0 callq *%rax
729: 90 nop
72a: c3 retq
...

Related

C: undefined reference to inline function

Since my last question was closed because of bad code style and typo, I reviewed it and ask for help again.
I'm trying to resolve a .exe file with PE format. Here is part of my code
#include "PE_resolve.h"
#define SIZEOF_SECTION_HEADER 0x28
/*load filebuffer into Imagebuffer*/
int Read_2_ImageBuffer(void **p_filebuffer, void **p_Imagebuffer,long filesize);
/*helper function*/
inline void * Get_NT_POS(void **p_filebuffer);
inline void * Get_FileHeader_POS(void **p_filebuffer);
inline void * Get_Opt_FileHeader_POS(void **p_filebuffer);
int main(){
return 0;
}
int Read_2_ImageBuffer(void **p_filebuffer, void **p_Imagebuffer,long filesize){
/*allocate memory for imagebuffer*/
void *Opt_PE_Header = Get_Opt_FileHeader_POS(p_filebuffer); //THE ERROR LINE
DWORD SizeOfImage = *(DWORD*) ((BYTE *)Opt_PE_Header + 0x38);
*p_Imagebuffer = malloc(SizeOfImage);
if(*p_Imagebuffer == NULL){
printf("can't allocate enough heap memory\n");
exit(EXIT_FAILURE);
}
memset(*p_Imagebuffer,0,SizeOfImage);
/*.....something deal the memory.....*/
return 0;
}
inline void * Get_NT_POS(void **p_filebuffer){
/*return void * point to NT_header in filebuffer*/
DWORD offset = *(DWORD*)((BYTE *)*p_filebuffer + 0x3c);
return (BYTE *)*p_filebuffer + offset;
}
inline void * Get_FileHeader_POS(void **p_filebuffer){
/*return void * point to PE_header in filebuffer*/
void *nt_pos = Get_NT_POS(p_filebuffer);
return (BYTE *)nt_pos + sizeof(DWORD);
}
inline void * Get_Opt_FileHeader_POS(void **p_filebuffer){
/*return void * point to option_PE_header in filebuffer*/
void *fileheader_pos = Get_FileHeader_POS(p_filebuffer);
return (BYTE *)fileheader_pos + 0x14;
}
And this is PE_resolve.h
#ifndef __PE_resolve_header
#define __PE_resolve_header
#define IMAGE_SIZEOF_SHORT_NAME 8
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char BYTE;
typedef short WORD;
typedef int DWORD;
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} _IMAGE_SECTION_HEADER;
#endif
when I compile it with MinGW, it follows with undefined reference to `Get_Opt_FileHeader_POS'
C:\MinGW\bin\gcc.exe -g D:\Compile\PE_resolve\PE_loader.c -o D:\Compile\PE_resolve\PE_loader.exe
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: C:\Users\15205\AppData\Local\Temp\ccadB6tt.o: in function `Read_2_ImageBuffer':
D:/Compile/PE_resolve/PE_loader.c:52: undefined reference to `Get_Opt_FileHeader_POS'
As you see, I implement all functions in this .c file with prototype at the beginning.
I'm a little frustrated. Could you please tell me the reason that cause the ERROR ?
Thx :(
You can add the static keyword before every inline function.
By doing that you force the linker to include the function symbol in the symbol table:
static inline void *Get_Opt_FileHeader_POS(void **p_filebuffer);
Another option is to simply remove the inline keyword.

x86_64 inline assembly function call

I tried to use inline assembly to call the function with three arguments, but it fails with Segmentation fault.
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <assert.h>
#include <stdlib.h>
void callee_test3(char* dest, char* src, size_t srclen)
{
printf("%s %s %li\n", dest, src, srclen);
};
int main()
{
char* dest = "test";
char* src = "src";
size_t srclen = 4;
asm(
"movq %[arg1], %%rdi\n\t"
"movq %[arg2], %%rsi\n\t"
"movq %[arg3], %%rdx\n\t"
"call *%[callee]"
:
:[arg1]"r"((u_int64_t)(dest)),
[arg2]"r"((u_int64_t)(src)),
[arg3]"r"((u_int64_t)(srclen)),
[callee]"r"(callee_test3)
:"cc"
);
return 0;
}
I can call a function with two arguments, but when I added into three arguments, it just failed. Tried to use gdb to trace where the code break it shows :
Breakpoint 1, main () at test.c:24
24 char* dest = "test";
(gdb) next
25 char* src = "src";
(gdb)
26 size_t srclen = 4;
(gdb)
34 :[arg1]"r"((u_int64_t)(dest)),
(gdb)
35 [arg2]"r"((u_int64_t)(src)),
(gdb)
28 asm(
(gdb)
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554872 in ?? ()
For some reasons, the third argument didn't store into the register. My assumption is I'm calling the wrong register to store the third argument. But I couldn't find the resource about that.

'arm-none-linux-gnueabi-gcc' vs. 'arm-linux-gnueabi-gcc' compilation difference

I'm writing a C program with inline assembly function that compares two strings if they are same.
When I compile it with 'arm-none-linux-gneabi-gcc' and 'arm-linux-gnueabi-gcc', the results are different. The difference seems to come from keyword 'none' which is place for [vendor] according to google search.
My questions are
Is this the cause of the difference in the results?
If so, what is set as [vendor] in 'arm-linux-gnueabi-gcc'?
My code :
#include <stdio.h>
int * intoneplus(int * i);
char * charoneplus(char * c);
int my_strcmp(const char *src1, const char *src2);
int main(void)
{
const char *a = "Hello world!";
const char *a1 = "Hello world!";
const char *a2 = "hello aorld!";
if(my_strcmp(a, a1)==0)
printf("a and a1 are same sentence\n");
else
printf("a and a1 are different\n");
if(my_strcmp(a, a2)==0)
printf("a and a2 are same sentence\n");
else
printf("a and a2 are different\n");
return 0;
}
int my_strcmp(const char *src1, const char *src2)
{
int ch1, ch2, ret=0;
__asm__ (
"loop:\n\t"
"LDRB %[ch1], [%[src1]], #1 \n\t LDRB %[ch2], [%[src2]], #1\n\t"
"CMP %[ch1], %[ch2]\n\t"
"MOVNE %[ret], #1\n\t BNE done \n\t"
"CMP %[ch1], #0\n\t BNE loop\n\t"
"done:\n\t"
:[ret]"=r"(ret)
:[src1]"r"(src1),[src2]"r"(src2),[ch1]"r"(ch1),[ch2]"r"(ch2)
);
return ret;
}
Compilation and execution results :
#ubuntu:~/test$ arm-linux-gnueabi-gcc -o practice2.out practice2.c -static
#ubuntu:~/test$ qemu-arm practice2.out
464281
a and a1 are different
1
a and a2 are different
#ubuntu:~/test$ arm-none-linux-gnueabi-gcc -o practice2.out practice2.c -static
#ubuntu:~/test$ qemu-arm practice2.out
0
a and a1 are same sentence
1
a and a2 are different

Error with address for jmp in inline assembly

What I do is
Get address of ExitProcess
Make space for opcode
Modify opcode in the space
Execute modified opcode by __asm__ ("jmp %%ecx"::"c"(opcode));
Here is my code:
#include <windows.h>
#include <stdio.h>
int main()
{
char addr[4];
*(int*)addr = GetProcAddress(GetModuleHandle("kernel32.dll"),"ExitProcess");
//push 0 == 0x6a 0x00
//call ExitProcess == 0xe8 0xd8 0x79 0xa2 0x75
char opcode[400] = {0x6a, 0x00, 0xe8,addr[0], addr[1],addr[2],addr[3]};
__asm__ ("jmp %%ecx" ::"c"(opcode));
//never be here
printf("never get here");
getchar();
return 0;
}
I expect program to exit normally, but the program terminates with a segmentation fault.
It seems that it jumps to somewhere, but not to the location I want it to jump.
How can I fix that?
Setting aside the odd thing you are trying to do...
Your problem is the opcode e8 is a relative jump. So you need to account for the address you are storing it at. Something like this maybe:
Update: Per taeyun, account for length of x.
#include <windows.h>
#include <stdio.h>
#pragma pack(1)
struct mfoo {
unsigned char x[3] = {0x6a, 0x00, 0xe8};
void *addr;
} foo;
int main()
{
unsigned char *a = (unsigned char *)GetProcAddress(GetModuleHandle("kernel32.dll"),"ExitProcess");
foo.addr = (void *)(a - sizeof(foo) - (unsigned char *)foo.x);
__asm__ ("jmp *%%ecx" ::"c"(&foo));
//never be here
printf("never get here");
getchar();
return 0;
}

Inline assembly in C program on x86_64 linux

I've built a short program written on C and inline assembly on my linux x86_64. It is supposed to write a string to stdout. I found it in an article on the internet:
int write_call( int fd, const char * str, int len ){
long __res;
__asm__ volatile ( "int $0x80":
"=a" (__res):"0"(__NR_write),"b"((long)(fd)),"c"((long)(str)),"d"((long)(len)) );
return (int) __res;
}
void do_write( void ){
char * str = "Paragon output string.\n";
int len = strlen( str ), n;
printf( "string for write length = %d\n", len );
n = write_call( 1, str, len );
printf( "write return : %d\n", n );
}
int main( int argc, char * argv[] ){
do_write();
return EXIT_SUCCESS;
}
But as I run it, it works incorrectly, making output
"write return : -14"
If I build and run it on 32-bit linux it does what is expected.
After some research I fount out that instruction "int $0x80" is a x86 instruction and truncates arguments in registers if called on x86_64.
But I couldn't find a proper substitution of "int $0x80" for x86_64 architecture. I have zero experience in assembly.
What should I put instead of "int $0x80" to receive expected result?
For amd64, you need to use "syscall" - and use different registers - instead of "int 0x80":
http://cs.lmu.edu/~ray/notes/linuxsyscalls/
http://blog.rchapman.org/post/36801038863/linux-system-call-table-for-x86-64
http://crypto.stanford.edu/~blynn/rop/
Here's a good example:
How to invoke a system call via sysenter in inline assembly (x86/amd64 linux)?
#include <unistd.h>
int main(void)
{
const char hello[] = "Hello World!\n";
const size_t hello_size = sizeof(hello);
ssize_t ret;
asm volatile
(
"movl $1, %%eax\n\t"
"movl $1, %%edi\n\t"
"movq %1, %%rsi\n\t"
"movl %2, %%edx\n\t"
"syscall"
: "=a"(ret)
: "g"(hello), "g"(hello_size)
: "%rdi", "%rsi", "%rdx", "%rcx", "%r11"
);
return 0;

Resources