Jens Kallup
2015-02-28 14:42:20 UTC
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
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