forked from chenxiaoyao/SoProtect
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathShell.cpp
More file actions
116 lines (102 loc) · 3.26 KB
/
Shell.cpp
File metadata and controls
116 lines (102 loc) · 3.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <elf.h>
#include <dlfcn.h>
#include <sys/mman.h>
#include "gdlfcn.h"
#include "Shell.h"
#include "Utils.h"
#include "Log.h"
#include "linker.h"
#define MAX_COUNT 64
static Shell *gshell = NULL;
void init() {
GLogInfo("Shell", "So shell library init....");
gshell = new Shell();
gshell->loadClientLibrary();
gshell->updateSoInfo();
}
void fini() {
if (gshell != NULL) {
GLogInfo("Shell", "So shell library finalize....");
gshell->restoreSoInfo();
delete gshell;
gshell = NULL;
}
}
Shell::Shell() {
MemoryMap map[MAX_COUNT];
int count = 0;
int ret = 0;
ret = loadMemoryMap(getpid(), map, &count);
if (ret < 0) {
GLogError("Shell", "Load process memory map failed. ");
abort();
return;
}
char *libName = NULL;
unsigned long initAddr = reinterpret_cast<unsigned long>(init);
for (int i = 0; i < count; i++) {
if (initAddr >= map[i].start && initAddr < map[i].end) {
libName = map[i].name;
break;
}
}
if (libName == NULL) {
GLogError("Shell", "Find current shell library failed. ");
abort();
return;
}
strncpy(this->libraryName, libName, sizeof(this->libraryName));
this->shellSoInfo = reinterpret_cast<soinfo *>(dlopen(libName, RTLD_LAZY));
}
void Shell::loadClientLibrary() {
GLogInfo("Shell", "Start to load client library...");
Elf_Ehdr *ehdr = reinterpret_cast<Elf_Ehdr *>(shellSoInfo->base);
Elf_Off clientLibOffset = ~ehdr->e_shoff;
GLogInfo("Shell", "Client so offset: %x", clientLibOffset);
this->clientSoInfo = reinterpret_cast<soinfo *>(gdlopen(this->libraryName, RTLD_LAZY, clientLibOffset));
GLogInfo("Shell", "Finish to load client library...");
}
void Shell::setSoInfoProtection(void *addr, int protection) {
void *pageStart = (void *) PAGE_START((Elf_Addr) addr);
if (mprotect(pageStart, PAGE_SIZE, protection) == -1) {
abort(); // Can't happen.
}
}
static void copyImportantSoInfo(soinfo *dest, soinfo *src) {
dest->load_bias = src->load_bias;
dest->base = src->base;
dest->size = src->size;
dest->strtab = src->strtab;
dest->symtab = src->symtab;
dest->nbucket = src->nbucket;
dest->nchain = src->nchain;
dest->bucket = src->bucket;
dest->chain = src->chain;
#ifdef ANDROID_ARM_LINKER
dest->ARM_exidx = src->ARM_exidx;
dest->ARM_exidx_count = src->ARM_exidx_count;
#endif
}
void Shell::updateSoInfo() {
this->backupShellSoInfo = *shellSoInfo;
this->setSoInfoProtection(this->shellSoInfo, PROT_READ | PROT_WRITE);
copyImportantSoInfo(this->shellSoInfo, this->clientSoInfo);
// restore soinfo reference count
if (this->shellSoInfo->ref_count > 1) {
this->shellSoInfo->ref_count--;
}
this->setSoInfoProtection(this->shellSoInfo, PROT_READ);
}
void Shell::restoreSoInfo() {
if (this->shellSoInfo == NULL || this->clientSoInfo == NULL) {
return;
}
this->setSoInfoProtection(this->shellSoInfo, PROT_READ | PROT_WRITE);
copyImportantSoInfo(this->shellSoInfo, &(this->backupShellSoInfo));
this->setSoInfoProtection(this->shellSoInfo, PROT_READ);
}
Shell::~Shell() {
gdlclose(this->clientSoInfo);
this->shellSoInfo = NULL;
this->clientSoInfo = NULL;
}