Discussion:
call crasht
(zu alt für eine Antwort)
Jens Kallup
2015-02-28 14:42:20 UTC
Permalink
Hallo Gemeinde,

wie lässt sich aus dem plugin eine function aus einer dll datei aufrufen?

$ gcc -O2 -o callreloc callreloc.c
$ gcc -o app.o -c app.s
$ cp app.o app.pi
$ objcopy -O binary app.pi
$ ./callreloc app

habe folgenden Code:

// callreloc.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <fcntl.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>

#include <errno.h>

#define PAGESIZE 4096

typedef unsigned int uint;
extern void (*start_app)(int,char**);

struct exports_entry
{
uint exp_name;
uint type;
uint func_off;
};

struct exports_table
{
int len;
struct exports_entry ee[];
};

// reflect the basic structure of a plugin
struct plugin
{
int magic; // "dynp"
int version;
uint name_off; // this can't be converted to full pointer
struct exports_table et;
};

// just a simple structure that contains all loaded plugins
struct container
{
struct plugin* base;
size_t size;
char* filename;
};


extern struct container plugins[]; // for simplicity, just a static array
extern int ploaded ; // count the plugins loaded


// c part
#include "callreloc.h"
#include "/usr/include/dlfcn.h"

void (*start_app)(int,char**) = NULL;

struct container plugins[10]; // for simplicity, just a static array
int ploaded=0; // count the plugins loaded

static void *lib_handle;

int v_argc;
char **v_argv;

extern void init_application(void);
static void (*MyPointer)();

void call_exported(void (*func)())
{
printf("STARTER\n");
func();
}

int load_plugin(char* aName)
{
int cnt;
int fd; // file descriptor
size_t sz; // filesize of plugin (rounded up to PAGESIZE)

struct stat sb; // stat buffer
struct plugin* pmap; // where the plugin is mapped

// add error checks
char* plugin = malloc(strlen(aName)+4); // append ".pi" extension
strcpy(plugin,aName);
strcat(plugin,".pi");

printf("trying to load dynamic plugin %s...\n",plugin);

if ((fd=open(plugin,O_RDONLY))==-1) // system call returns -1 on error
{
printf("could not open %s...\n",plugin);
goto error_need_free;
}

if ((sz=fstat(fd,&sb))==-1) // system call returns -1 on error
{
printf("could not stat %s (fd %d)...\n",plugin,fd);
goto error_need_close;
}

sz=sb.st_size;
sz+=(PAGESIZE-(sz & (PAGESIZE - 1))); // align to page size

if
(!(pmap=mmap(NULL,sz,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE,fd,0)))
{
printf("could not map %s into memory...\n",plugin);
goto error_need_close;
}

// the plugin is now loaded at pmap
// it starts with 4 byte magic number (which we check first),

if (pmap->magic!=0x706e7964)
{
printf("%s is not a valid plugin...\n",plugin);
goto error_need_unmap;
}

printf("plugin loaded at %p\n",pmap);

plugins[ploaded].base=pmap;
plugins[ploaded].size=sz;
plugins[ploaded].filename=plugin;

printf("exports table at %p, length %d\n",&pmap->et,pmap->et.len);

for (cnt=0;cnt<pmap->et.len;cnt++)
{
void (*r)() = NULL;
char* name = (char*)pmap + pmap->et.ee[cnt].exp_name;
void (*fptr)(int,char**);

if (strcmp(name,"start"))
{
fptr = dlsym(lib_handle, name);
if (dlerror() != NULL) {
printf("dlsym: %s\n", dlerror());
exit(1);
}

MyPointer = (void (*)())fptr;
pmap->et.ee[cnt].func_off = MyPointer;
r = MyPointer;

//MyPointer(); // works

pmap->et.ee[cnt].func_off = r;
printf(" %d: function %s at offset 0x%x, Relocated to %x\n",
cnt+1,
name,
pmap->et.ee[cnt].func_off,
r
);
}
else {
//if (pmap->et.ee[cnt].func_off)
r = pmap->et.ee[cnt].func_off;

printf(" %d: function %s at offset 0x%x, relocated to %p\n",
cnt+1,
(char*)pmap + pmap->et.ee[cnt].exp_name,
pmap->et.ee[cnt].func_off,
r
);
}
}

// now we can't relocate the plugin's name on the fly, since it
// is only 32 bits, but the pointer would take 64 bits
printf("plugin name at offset 0x%x\n",pmap->name_off);
printf("%s\n",(char*)pmap + pmap->name_off);

ploaded++;

close(fd);
return 0;

error_need_unmap: munmap(pmap,sz);
error_need_close: close(fd);
error_need_free: free(plugin);

return -1;
}

void cleanup_plugins()
{
int cnt;
for (cnt=ploaded-1; cnt>=0; cnt--)
{
printf("unloading
%s\n",(char*)plugins[cnt].base+plugins[cnt].base->name_off);
free(plugins[cnt].filename);
plugins[cnt].filename=NULL;
munmap(plugins[cnt].base,plugins[cnt].size);
plugins[cnt].base=NULL;
}

ploaded = 0;
}

// --------------------------------------
// query plugin function by plugin number
// (index in global plugins[])
// --------------------------------------
void* query_function_an(char* aName, int aPlugin)
{
struct plugin* p=plugins[aPlugin].base;
int cnt;

for (cnt=0; cnt<p->et.len; cnt++)
{
if (strcmp((char*)p + p->et.ee[cnt].exp_name,aName)==0)
{
if (!(p->et.ee[cnt].func_off))
break;
return (char*)p + p->et.ee[cnt].func_off;
}
}
return NULL;
}

// query pluginfunction by plugin name and version
// meaning that the plugin must _at least_ be that version
void* query_function_aan(char* aName, char* aPlugin, int aVersion)
{
struct plugin* p;
int cnt_p;
int cnt_f;

for (cnt_p=0; cnt_p<ploaded; cnt_p++)
{
printf("looking up plugin %d for %s\n",cnt_p,aName);
p=plugins[cnt_p].base;
if (strcmp((char*)p+p->name_off,aPlugin)==0)
{
if (p->version>=aVersion)
{
for (cnt_f=0; cnt_f<p->et.len; cnt_f++)
{
if (strcmp((char*)p + p->et.ee[cnt_f].exp_name,aName)==0)
{
if (!(p->et.ee[cnt_f].func_off))
break;
return (char*)p + p->et.ee[cnt_f].func_off;
}
}
printf(" not found\n");
}
else
printf(" wrong version (%x < %x)\n",p->version,aVersion);
}
}
return NULL;
}

int main(int argc, char** argv)
{
v_argc = argc;
v_argv = argv;

if (argc == 1)
{
printf("no plugin specified, exiting...\n");
return 1;
}

lib_handle = dlopen("libkbase.so.1", RTLD_LAZY);
if (!lib_handle) {
printf("dlopen: %s\n", dlerror());
exit(1);
}

int cnt;

for (cnt=0; cnt<argc-1; cnt++)
load_plugin(argv[cnt+1]);

if (ploaded==0)
{
printf("could not load any of the specified plugins...\n");
return 2;
}

start_app = query_function_aan("start", "app", 0);
printf("start.app at: %p\n",start_app);

start_app(argc, argv);

cleanup_plugins();
return 0;
}


// assembler part: app.s
.org 0
.ascii "dynp"
.long 0x00010001
.long plugin_name - .text

exports_len:
.long (end_of_table-exports)/12
exports:
.long start_symbol - .text
.long 0
.long start_function - .text

.long init_application_symbol - .text
.long 2
export_call__init_app:
.long 0

//.include "plugin_exports.s"
end_of_table:

start_symbol:
.asciz "start"

init_application_symbol:
.asciz "init_application"

start_function:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp

movl export_call__init_app(%rip), %eax
call *%rax
leave
ret

plugin_name:
.asciz "app"

Gruß
Jens
Bernhard Schornak
2015-03-01 15:59:25 UTC
Permalink
Post by Jens Kallup
Hallo Gemeinde,
wie lässt sich aus dem plugin eine function aus einer dll datei aufrufen?
call *__imp__WantedDllFunction(%rip)

Meine API-Wrapper

https://code.google.com/p/st-open/source/browse/LIB/SOURCES/core/cap.S

funktionieren auf diese Art und Weise. Wenn Funktionen in einer
"Third-Party-DLL" aufgerufen werden sollen, muss die DLL zuerst
geladen (aka "importiert") werden, um sie über RIP addressieren
zu können:

http://de.wikipedia.org/wiki/Dynamic_Link_Library


Grüsse aus Augsburg

Bernhard Schornak

Loading...