Private loading not working on Android 9
Created by: summershrimp
The Bionic library for Android 9 have changes from Android 6 that fails dynamorio.
Below is a small trick to get it working, but not a perfectly way.
In order to running dynamorio on android9-arm64, we change privload_call_lib_func
diff --git a/core/unix/loader.c b/core/unix/loader.c
index 89d5d31c..00c3519e 100644
--- a/core/unix/loader.c
+++ b/core/unix/loader.c
@@ -911,7 +911,7 @@ privload_call_lib_func(fp_t func)
*/
dummy_argv[0] = dummy_str;
dummy_argv[1] = NULL;
- func(1, dummy_argv, our_environ);
+ //func(1, dummy_argv, our_environ);
}
bool
Firstly, we thought programs with init
or init_array
would behave abnormal, but a few testcases shows that It's working perfectly. Then we thought the module load callback would behave abnormal, but it also works.
The question is, what's really happening when call init functions from dynamorio privload? What would failed if we don't call init functions from dynamorio privload?
PS. Testing with libinscount.so with patch below.
+++ b/api/samples/inscount.cpp
@@ -85,6 +85,14 @@ static dr_emit_flags_t
event_app_instruction(void *drcontext, void *tag, instrlist_t *bb, instr_t *inst,
bool for_trace, bool translating, void *user_data);
+static void
+event_module_load(void *drcontext, const module_data_t *info, bool loaded)
+{
+ const char *module_name = dr_module_preferred_name(info);
+ dr_fprintf(STDOUT, "Module Name: %s\n", module_name);
+
+}
+
DR_EXPORT void
dr_client_main(client_id_t id, int argc, const char *argv[])
{
@@ -108,6 +116,7 @@ dr_client_main(client_id_t id, int argc, const char *argv[])
dr_register_exit_event(event_exit);
drmgr_register_bb_instrumentation_event(event_bb_analysis, event_app_instruction,
NULL);
+ drmgr_register_module_load_event(event_module_load);
/* make it easy to tell, by looking at log file, which client executed */
dr_log(NULL, DR_LOG_ALL, 1, "Client 'inscount' initializing\n");
Testing program:
bad_case.cpp:
// g++ bad_case.cpp -o bad_case.so -fPIC -shared
#include <cassert>
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
unsigned long global_magic;
__attribute__((constructor)) static void initall(){
global_magic = 0xdead0000;
printf("global_magic: %lx\n", global_magic);
}
__attribute__((destructor)) static void deinitall(){
global_magic = 0;
printf("global_magic: %lx\n", global_magic);
}
class BadClass{
public:
BadClass() {
this->magic_number = global_magic;
this->add_number = 0xbeef;
this->magic_number = this->magic_number + this->add_number;
}
bool isOK(){
printf("%lx\n", this->magic_number);
return this->magic_number == 0xdeadbeef;
}
~BadClass() {
printf("deconstruct\n");
this->magic_number = 0;
}
private:
unsigned long magic_number;
unsigned long add_number;
};
BadClass globalbad;
extern "C"{
int bad_case(void) {
char tmp[4096];
int cnt;
assert(globalbad.isOK());
int fd = open("/proc/self/maps", O_RDONLY);
while((cnt = read(fd, tmp, 4096)) != 0)
write(1, tmp, cnt);
return 0;
}
}
main.c:
// gcc main.c -o main -fPIE -pie -ldl
#include <dlfcn.h>
#include <stdlib.h>
int (*bad_case)(void);
int main(void){
void* handle = dlopen("./bad_case.so", RTLD_LAZY);
if(!handle) {
perror("dlopen");
exit(-1);
}
bad_case = dlsym(handle, "bad_case");
if(!bad_case) {
perror("dlsym");
exit(-1);
}
bad_case();
}