Address of externed array differs between compilation units - c

I have an array foo declared in a C file, which is then declared as extern in the corresponding header. I then access foo from another file, but the address of the first element in the array is an invalid address, and differs from that in the compilation unit where foo is defined. This has been built from the Pebble SDK, using ARM CodeSourcery compilers.
Example code:
test1.h
extern int foo[];
void testRoutine();
test1.c
#include <pebble.h>
#include "test1.h"
void testRoutine()
{
APP_LOG(APP_LOG_LEVEL_INFO, "Hello World! foo: 0x%x", (unsigned int)&foo[0]);
}
int foo[] = {1,2,3,4,5,6};
main.c
#include <pebble.h>
#include "test1.h"
int main()
{
APP_LOG(APP_LOG_LEVEL_INFO, "Start of test");
testRoutine(); // Print the address of foo from the perspective of test1.c
APP_LOG(APP_LOG_LEVEL_INFO, "foo: 0x%x", (unsigned int)&foo[0]);
return 0;
}
Expected output:
Start of test
Hello World! foo: 0x12345678
foo: 0x12345678
Actual output:
Start of test
Hello World! foo: 0x20081234
foo: 0x21941234 (placeholders, I can't get the real addresses right now)
This code works as expected in standard x86 GCC, but does not work on the ARM compiler. Have I messed up the code, or is there a compiler bug here?

I tried to reproduce your problem without success on Debian 64 bits:
Main.c:
#include <stdio.h>
#include "test1.h"
int main()
{
testRoutine(); // Print the address of foo from the perspective of test1.c
printf("foo: 0x%x\n", (unsigned int)&foo[0]);
return 0;
}
test1.h:
extern int foo[];
void testRoutine();
test1.c:
#include <stdio.h>
#include "test1.h"
void testRoutine()
{
printf("Hello World! foo: 0x%x\n", (unsigned int)&foo[0]);
}
int foo[] = {1,2,3,4,5,6};
The result is:
$ ./program
Hello World! foo: 0x600970
foo: 0x600970
However gcc warnings are explicit:
test1.c:7:38: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
You should try with:
APP_LOG(APP_LOG_LEVEL_INFO, "foo: 0x%p", &foo[0]);
Edit:
Since you said you are running it on a 32 bits platform where sizeof(unsigned int)==sizeof(int *), the cast is not the problem. There is some other problem in your program unrelated to this code (stack corruption?).

Related

return WCHAR[] in C

I have the following code written in C:
#include <windows.h>
#include <stdio.h>
WCHAR* test(){
WCHAR var[256];
int nSize = GetEnvironmentVariableW(L"SystemRoot", NULL, 0);
GetEnvironmentVariableW(L"SystemRoot", &var, nSize);
wprintf(L"%s\n", var);
return var;
}
int main() {
WCHAR* var = test();
wprintf(L"%s\n", var);
return 0;
}
When I compile it in Visual Studio and run it it works as expected. It prints result two times - in main func and in test. Output is:
C:\Windows
C:\Windows
But when I compile it on linux with mingw compiler via command
i686-w64-mingw32-gcc -o test.exe -O3 -Os -static -s test.c
it gives this output after starting:
C:\Windows
(null)
Why do the test() func return NULL when I'm using mingw and what to do to make it work properly?
Thanks.
You cannot return the address of a local variable, you get a compiler warning (which is actually more of an error).
You want this:
#include <windows.h>
#include <stdio.h>
WCHAR* test(WCHAR var[], int nSize) {
GetEnvironmentVariableW(L"SystemRoot", var, nSize);
wprintf(L"%s\n", var);
return var;
}
int main() {
// declare var outside the test function
WCHAR var[256];
// pass the address of var to test
test(var, 256);
wprintf(L"%s\n", var);
return 0;
}
But be aware that 256 (like in var[256]) may not be enough. I leave it as an exercise to you to resolve this issue properly.

How call and compile function from elf to my binary?

I have a binary file (ELF) that I don't write, but I want to use 1 function from this binary (I know the address/offset of the function), that function not exported from the binary.
My goal is to call this function from my C code that I write and compile this function statically in my binary (I compile with gcc).
How can I do that please?
I am going to answer the
call to this function from my c code that I write
part.
The below works under certain assumptions, like dynamic linking and position independent code. I haven't thought for too long about what happens if they are broken (let's experiment/discuss, if there's interest).
$ cat lib.c
int data = 42;
static int foo () { return data; }
gcc -fpic -shared lib.c -o lib.so
$ nm lib.so | grep foo
00000000000010e9 t foo
The above reproduces having the address that you know. The address we know now is 0x10e9. It is the virtual address of foo before relocation. We'll model the relocation the dynamic loader does by hand by simply adding the base address at which lib.so gets loaded.
$ cat 1.c
#define _GNU_SOURCE
#include <stdio.h>
#include <link.h>
#include <string.h>
#include <elf.h>
#define FOO_VADDR 0x10e9
typedef int(*func_t)();
int callback(struct dl_phdr_info *info, size_t size, void *data)
{
if (!(strstr(info->dlpi_name, "lib.so")))
return 0;
Elf64_Addr addr = info->dlpi_addr + FOO_VADDR;
func_t f = (func_t)addr;
int res = f();
printf("res = %d\n", res);
return 0;
}
int main()
{
void *handle = dlopen("./lib.so", RTLD_LAZY);
if (!handle) {
puts("failed to load");
return 1;
}
dl_iterate_phdr(&callback, NULL);
dlclose(handle);
return 0;
}
And now...
$ gcc 1.c -ldl && ./a.out
res = 42
Voila -- it worked! That was fun.
Credit: this was helpful.
If you have questions, feel free to read the man and ask in the comments.
As for
compile this function statically in my binary
I don't know off the bat. This would be trickier. Why do you want that? Also, do you know whether the function depends on some data (or maybe it calls other functions) in the original ELF file, like in the example above?

call function from address in commandline

i wrote this code for call function from there address:
$ cat main.c
#include <stdlib.h>
#include <stdio.h>
int test(){
printf("%s\n","[*] i'm in test");
return 1;
}
int main(int argc,char **argv){
int (*m)();
m=&test;
printf("[*] test func addr is: %p\n", m);
(*m)();
return 0;
}
$ gcc -o main main.c
$ ./main
[*] test func addr is: 0x8048414
[*] i'm in test
$
no problem
but i want run function, and pass there address from argv in commandline..
for example if address of function test() is 0x222222, i want after run program with this command ./main 222222, test() function run ..
my code is:
$ cat main.c
#include <stdlib.h>
#include <stdio.h>
int test(){
printf("%s\n","[*] i'm in test");
return 1;
}
int main(int argc,char **argv){
int (*m)();
long conv ;
int num;
num=conv=strtol(argv[1],NULL,10);
printf("[*] argv[1] is: %d\n", num);
m=&test;
printf("[*] test func addr is: %p\n", m);
m=num;
(*m)();
return 0;
}
$ gcc -o main main.c
main.c: In function ‘main’:
main.c:17:3: warning: assignment makes pointer from integer without a cast [enabled by default]
$ ./main 8048444
[*] argv[1] is: 8048444
[*] test func addr is: 0x8048444
Segmentation fault (core dumped)
$
but no run!
However, it is true that instead of 10 you should use 16 because addresses are always in hexadecimal format but your code will still run fine even if the argument is 10. Your code is producing segmentation fault because of this assignment: m=num. This assigns an arbitrary value to m instead of address of test and on calling (*m)() a segmentation fault is produced as m is pointing to an invalid location. You should change the last two lines as:
num=m;
(*num)();
This would run the test function properly.
Memory addresses are in base 16 not base 10
try changing strtol(argv[1],NULL,10); to strtol(argv[1],NULL,16);

Replace #define X macro value with another one specified in compilation command

Given the following code:
#include <stdio.h>
#ifndef STR
#define STR "HELLO"
#endif
int main() {
printf(STR "WORLD \n");
return 0;
}
which says: if STR was not defined, then define it to be "HELLO",
so the output will be
HELLO WORLD
How can I modify the value of STR when compiling using gcc?
I've tried
gcc -Wall program.c -DSTR="HI" -o program
but it didn't produce the expected output.
Try in the form of:
-DSTR=\"MyString\"

C: Run machine code from memory

I want to execute some code from memory; my longterm goal is to create a self-decrypting app. To understand the matter I started from the roots.
I created the following code:
#define UNENCRYPTED true
#define sizeof_function(x) ( (unsigned long) (&(endof_##x)) - (unsigned long) (&x))
#define endof_function(x) void volatile endof_##x() {}
#define DECLARE_END_OF_FUNCTION(x) void endof_##x();
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
unsigned char *bin;
#ifdef UNENCRYPTED
void hexdump(char *description, unsigned char *toDump, unsigned long length) {
printf("Hex-dump of \"%s\":\n", description);
for (int i = 0; i < length; i++) {
printf("%02x", toDump[i]);
}
printf("\n");
}
void hello_world() {
printf("Hello World!\n");
}
endof_function(hello_world);
#endif
int main (void) {
errno = 0;
unsigned long hello_worldSize = sizeof_function(hello_world);
bin = malloc(hello_worldSize);
//Compute the start of the page
size_t pagesize = sysconf(_SC_PAGESIZE);
uintptr_t start = (uintptr_t) bin;
uintptr_t end = start + (hello_worldSize);
uintptr_t pagestart = start & -pagesize;
bin = (void *)pagestart;
//Set mprotect for bin to write-only
if(mprotect(bin, end - pagestart, PROT_WRITE) == -1) {
printf("\"mprotect\" failed; error: %s\n", strerror(errno));
return(1);
}
//Get size and adresses
unsigned long hello_worldAdress = (uintptr_t)&hello_world;
unsigned long binAdress = (uintptr_t)bin;
printf("Address of hello_world %lu\nSize of hello_world %lu\nAdress of bin:%lu\n", hello_worldAdress, hello_worldSize, binAdress);
//Check if hello_worldAdress really points to hello_world()
void (*checkAdress)(void) = (void *)hello_worldAdress;
checkAdress();
//Print memory contents of hello_world()
hexdump("hello_world", (void *)&hello_world, hello_worldSize);
//Copy hello_world() to bin
memcpy(bin, (void *)hello_worldAdress, hello_worldSize);
//Set mprotect for bin to read-execute
if(mprotect(bin, end - pagestart, PROT_READ|PROT_EXEC) == -1) {
printf("\"mprotect\" failed; error: %s\n", strerror(errno));
return(1);
}
//Check if the contents at binAdress are the same as of hello_world
hexdump("bin", (void *)binAdress, hello_worldSize);
//Execute binAdress
void (*executeBin)(void) = (void *)binAdress;
executeBin();
return(0);
}
However I get an segfault-error; the programs output is the following:
(On OS X; i86-64):
Adress of hello_world 4294970639
Size of hello_world 17
Adress of bin:4296028160
Hello World!
Hex-dump of "hello_world":
554889e5488d3d670200005de95a010000
Hex-dump of "bin":
554889e5488d3d670200005de95a010000
Program ended with exit code: 9
And on my Raspi (Linux with 32-Bit ARM):
Adress of hello_world 67688
Size of hello_world 36
Hello World!
Hello World!
Hex-dump of "hello_world":
00482de90db0a0e108d04de20c009fe512ffffeb04008de50bd0a0e10088bde8d20b0100
Hex-dump of "bin":
00482de90db0a0e108d04de20c009fe512ffffeb04008de50bd0a0e10088bde8d20b0100
Speicherzugriffsfehler //This is german for memory access error
Where is my mistake?
The problem was, that the printf-call in hello_world is based on a relative jump address, which of course doesn't work in the copied function.
For testing purposes I changed hello_world to:
int hello_world() {
//_printf("Hello World!\n");
return 14;
}
and the code under "//Execute binAdress" to:
int (*executeBin)(void) = (void *)binAdress;
int test = executeBin();
printf("Value: %i\n", test);
which prints out 14 :D
On ARM, you have to flush the instruction cache using a function like cacheflush, or your code may not run properly. This is required for self-modifying code and JIT compilers, but is not generally needed for x86.
Additionally, if you move a chunk of code from one location to another, you have to fixup any relative jumps. Typically, calls to library functions are implemented as jumps to a relocation section, and are often relative.
To avoid having to fixup jumps, you can use some linker tricks to compile code to start at a different offset. Then, when decrypting, you simply load the decrypted code to that offset. A two-stage compilation process is usually used: compile your real code, append the resulting machine code to your decryption stub, and compile the whole program.

Resources