apk加固-加密so-native层解密

so中节加密

c语言处理文件格式写好写点:
注意点:

  1. 加密时遍历节找到名字(存的是相对于字串节的地址偏移)加密,并将节偏移存到头的节偏移处,节大小和页数存到头的入口点处,为了方便解密时查找,同时这俩项对so加载无用。破坏section,但可从p节读出结构。
  2. 解密函数在init中解密,用属性声明为特殊段,init执行时文件已经加载,可以修改。
  3. linker等native的加载源码需要熟
  4. 头、节等都是基于装载地址映射的,节等按头加载,代码和数据用重定位定位。因此修改节内数据、节数据、头数据只要文件偏移+装载地址即可。
  5. c语言对文件格式读取与细节处理比java来的方便。清晰
  6. 操作步骤:写好so与解密函数,编译后用加密程序处理。

加密代码c:

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 <stdio.h>
#include <fcntl.h>
#include "elf.h"
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv){
char *encodeSoName = "libdemo.so";
char target_section[] = ".mytext";
char *shstr = NULL;
char *content = NULL;
Elf32_Ehdr ehdr;
Elf32_Shdr shdr;
int i;
unsigned int base, length;
unsigned short nsize;
unsigned char block_size = 16;
int fd;
fd = open(encodeSoName, O_RDWR);
if(fd < 0){
printf("open %s failed\n", argv[1]);
goto _error;
}
//读文件头,结构体不用声明为不对齐?
if(read(fd, &ehdr, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)){
puts("Read ELF header error");
goto _error;
}
//String Section头
lseek(fd, ehdr.e_shoff + sizeof(Elf32_Shdr) * ehdr.e_shstrndx, SEEK_SET);
if(read(fd, &shdr, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)){
puts("Read ELF section string table error");
goto _error;
}
//分配字符串空间
if((shstr = (char *) malloc(shdr.sh_size)) == NULL){
puts("Malloc space for section string table failed");
goto _error;
}
//读string section
lseek(fd, shdr.sh_offset, SEEK_SET);
if(read(fd, shstr, shdr.sh_size) != shdr.sh_size){
puts("Read string table failed");
goto _error;
}
//遍历Section
lseek(fd, ehdr.e_shoff, SEEK_SET);
for(i = 0; i < ehdr.e_shnum; i++){
if(read(fd, &shdr, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)){
puts("Find section .text procedure failed");
goto _error;
}
if(strcmp(shstr + shdr.sh_name, target_section) == 0){
base = shdr.sh_offset;
length = shdr.sh_size;
printf("Find section %s\n", target_section);
break;
}
}
//读取指定节
lseek(fd, base, SEEK_SET);
content = (char*) malloc(length);
if(content == NULL){
puts("Malloc space for content failed");
goto _error;
}
if(read(fd, content, length) != length){
puts("Read section .text failed");
goto _error;
}
//将Section的size和base写入到Elf的header中的e_entry和e_shoff
//这里是计算Section占用内存的几页用原来申请权限,一个页的大小是:0x1000=4096
nsize = length / 4096 + (length % 4096 == 0 ? 0 : 1);
printf("base = %x, length = %x\n", base, length);
printf("entry:%x\n",((length << 16) + nsize));
//节长<<16+页数
ehdr.e_entry = (length << 16) + nsize;
ehdr.e_shoff = base;//加密节偏移相对装载地址
//对内容进行加密
for(i=0;i<length;i++){
content[i] = ~content[i];
}
//重写Elf的头部信息
lseek(fd, 0, SEEK_SET);
if(write(fd, &ehdr, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)){
puts("Write ELFhead to .so failed");
goto _error;
}
//将加密之后的section回写
lseek(fd, base, SEEK_SET);
if(write(fd, content, length) != length){
puts("Write modified content to .so failed");
goto _error;
}
//释放资源
puts("Completed");
_error:
free(content);
free(shstr);
close(fd);
return 0;
}

解密代码:

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
#include <jni.h>
#include <stdio.h>
#include <android/log.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <elf.h>
#include <sys/mman.h>
//要保护函数 声明时属性可放于后面
jstring getString(JNIEnv*) __attribute__((section (".mytext")));
jstring getString(JNIEnv* env){
return (*env)->NewStringUTF(env, "Native method return!");
};
//解密函数
void init_getString() __attribute__((constructor));
unsigned long getLibAddr();
void init_getString(){
char name[15];
unsigned int nblock;
unsigned int nsize;
unsigned long base;
unsigned long text_addr;
unsigned int i;
Elf32_Ehdr *ehdr;
Elf32_Shdr *shdr;
//获取so的起始地址
base = getLibAddr();
//获取指定section的偏移值和size
ehdr = (Elf32_Ehdr *)base;
text_addr = ehdr->e_shoff + base;
nblock = ehdr->e_entry >> 16;
nsize = ehdr->e_entry & 0xffff;
__android_log_print(ANDROID_LOG_INFO, "JNITag", "nblock = 0x%x,nsize:%d", nblock,nsize);
__android_log_print(ANDROID_LOG_INFO, "JNITag", "base = 0x%x", text_addr);
printf("nblock = %d\n", nblock);
//修改内存的操作权限
if(mprotect((void *) (text_addr / PAGE_SIZE * PAGE_SIZE), 4096 * nsize, PROT_READ | PROT_EXEC | PROT_WRITE) != 0){
puts("mem privilege change failed");
__android_log_print(ANDROID_LOG_INFO, "JNITag", "mem privilege change failed");
}
//解密
for(i=0;i< nblock; i++){
char *addr = (char*)(text_addr + i);
*addr = ~(*addr);
}
if(mprotect((void *) (text_addr / PAGE_SIZE * PAGE_SIZE), 4096 * nsize, PROT_READ | PROT_EXEC) != 0){
puts("mem privilege change failed");
}
puts("Decrypt success");
}
unsigned long getLibAddr(){
unsigned long ret = 0;
char name[] = "libdemo.so";
char buf[4096], *temp;
int pid;
FILE *fp;
pid = getpid();
sprintf(buf, "/proc/%d/maps", pid);
fp = fopen(buf, "r");
if(fp == NULL)
{
puts("open failed");
goto _error;
}
while(fgets(buf, sizeof(buf), fp)){
if(strstr(buf, name)){
temp = strtok(buf, "-");
ret = strtoul(temp, NULL, 16);
break;
}
}
_error:
fclose(fp);
return ret;
}
JNIEXPORT jstring JNICALL
Java_com_example_shelldemo_MainActivity_getString( JNIEnv* env,
jobject thiz )
{
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#define ABI "armeabi-v7a/NEON"
#else
#define ABI "armeabi-v7a"
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#elif defined(__mips__)
#define ABI "mips"
#else
#define ABI "unknown"
#endif
return getString(env);
}

so中函数加密

so函数:(被用)
过程:符号表导出->函数代码
保护:导出符号不可改->hook->加密代码
看下linker过程,有漏洞可以更强加密说不定

思路1:根据dynsym与dynstr定位到需要的函数地址,加密,解密时直接用指针函数就行。指针函数引用的地方会被重定位到dynsym指定地点(已经加载好的符号),所以解密方便。全局符号表先收集符号再重定位。

书中思路:根据dyn中的hash(用于快速导出)找到指定函数加密。

加密:

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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#include <stdio.h>
#include <fcntl.h>
#include "elf.h"
#include <stdlib.h>
#include <string.h>
typedef struct _funcInfo{
Elf32_Addr st_value;
Elf32_Word st_size;
}funcInfo;
Elf32_Ehdr ehdr;
//For Test
static void print_all(char *str, int len){
int i;
for(i=0;i<len;i++)
{
if(str[i] == 0)
puts("");
else
printf("%c", str[i]);
}
}
//标准的hash函数
static unsigned elfhash(const char *_name)
{
const unsigned char *name = (const unsigned char *) _name;
unsigned h = 0, g;
while(*name) {
h = (h << 4) + *name++;
g = h & 0xf0000000;
h ^= g;
h ^= g >> 24;
}
return h;
}
//寻找到目标的段
static Elf32_Off findTargetSectionAddr(const int fd, const char *secName){
Elf32_Shdr shdr;
char *shstr = NULL;
int i;
lseek(fd, 0, SEEK_SET);
if(read(fd, &ehdr, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)){
puts("Read ELF header error");
goto _error;
}
lseek(fd, ehdr.e_shoff + sizeof(Elf32_Shdr) * ehdr.e_shstrndx, SEEK_SET);
if(read(fd, &shdr, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)){
puts("Read ELF section string table error");
goto _error;
}
if((shstr = (char *) malloc(shdr.sh_size)) == NULL){
puts("Malloc space for section string table failed");
goto _error;
}
lseek(fd, shdr.sh_offset, SEEK_SET);
if(read(fd, shstr, shdr.sh_size) != shdr.sh_size){
puts(shstr);
puts("Read string table failed");
goto _error;
}
lseek(fd, ehdr.e_shoff, SEEK_SET);
for(i = 0; i < ehdr.e_shnum; i++){
if(read(fd, &shdr, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)){
puts("Find section .text procedure failed");
goto _error;
}
if(strcmp(shstr + shdr.sh_name, secName) == 0){
printf("Find section %s, addr = 0x%x\n", secName, shdr.sh_offset);
break;
}
}
free(shstr);
return shdr.sh_offset;
_error:
return -1;
}
//找到指定的函数的基地址和大小存入到info结构体中
static char getTargetFuncInfo(int fd, const char *funcName, funcInfo *info){
char flag = -1, *dynstr;
int i;
Elf32_Sym funSym;
Elf32_Phdr phdr;
Elf32_Off dyn_off;
Elf32_Word dyn_size, dyn_strsz;
Elf32_Dyn dyn;
Elf32_Addr dyn_symtab, dyn_strtab, dyn_hash;
unsigned funHash, nbucket, nchain, funIndex;
//从程序头中查找类型为PT_DYNAMIC的Segment
lseek(fd, ehdr.e_phoff, SEEK_SET);
for(i=0;i < ehdr.e_phnum; i++){
if(read(fd, &phdr, sizeof(Elf32_Phdr)) != sizeof(Elf32_Phdr)){
puts("Read segment failed");
goto _error;
}
if(phdr.p_type == PT_DYNAMIC){
dyn_size = phdr.p_filesz;
dyn_off = phdr.p_offset;
flag = 0;
printf("Find section %s, size = 0x%x, addr = 0x%x\n", ".dynamic", dyn_size, dyn_off);
break;
}
}
if(flag){
puts("Find .dynamic failed");
goto _error;
}
flag = 0;
printf("dyn_size:%d\n",dyn_size);
printf("count:%d\n",(dyn_size/sizeof(Elf32_Dyn)));
printf("off:%x\n",dyn_off);
//在动态段中找到对应的section
lseek(fd, dyn_off, SEEK_SET);
for(i=0;i < dyn_size / sizeof(Elf32_Dyn); i++){
int sizes = read(fd, &dyn, sizeof(Elf32_Dyn));
if(sizes != sizeof(Elf32_Dyn)){
puts("Read .dynamic information failed");
//goto _error;
break;
}
if(dyn.d_tag == DT_SYMTAB){
dyn_symtab = dyn.d_un.d_ptr;
flag += 1;
printf("Find .dynsym, addr = 0x%x, val = 0x%x\n", dyn_symtab, dyn.d_un.d_val);
}
if(dyn.d_tag == DT_HASH){
dyn_hash = dyn.d_un.d_ptr;
flag += 2;
printf("Find .hash, addr = 0x%x\n", dyn_hash);
}
if(dyn.d_tag == DT_STRTAB){
dyn_strtab = dyn.d_un.d_ptr;
flag += 4;
printf("Find .dynstr, addr = 0x%x\n", dyn_strtab);
}
if(dyn.d_tag == DT_STRSZ){
dyn_strsz = dyn.d_un.d_val;
flag += 8;
printf("Find .dynstr size, size = 0x%x\n", dyn_strsz);
}
}
if((flag & 0x0f) != 0x0f){
puts("Find needed .section failed\n");
goto _error;
}
dynstr = (char*) malloc(dyn_strsz);
if(dynstr == NULL){
puts("Malloc .dynstr space failed");
goto _error;
}
lseek(fd, dyn_strtab, SEEK_SET);
if(read(fd, dynstr, dyn_strsz) != dyn_strsz){
puts("Read .dynstr failed");
goto _error;
}
funHash = elfhash(funcName);
printf("Function %s hashVal = 0x%x\n", funcName, funHash);
lseek(fd, dyn_hash, SEEK_SET);
if(read(fd, &nbucket, 4) != 4){
puts("Read hash nbucket failed\n");
goto _error;
}
printf("nbucket = %d\n", nbucket);
if(read(fd, &nchain, 4) != 4){
puts("Read hash nchain failed\n");
goto _error;
}
printf("nchain = %d\n", nchain);
funHash = funHash % nbucket;
printf("funHash mod nbucket = %d \n", funHash);
lseek(fd, funHash * 4, SEEK_CUR);
if(read(fd, &funIndex, 4) != 4){
puts("Read funIndex failed\n");
goto _error;
}
printf("funcIndex:%d\n", funIndex);
lseek(fd, dyn_symtab + funIndex * sizeof(Elf32_Sym), SEEK_SET);
if(read(fd, &funSym, sizeof(Elf32_Sym)) != sizeof(Elf32_Sym)){
puts("Read funSym failed");
goto _error;
}
//这里开始查找hash中目标函数的idnex
if(strcmp(dynstr + funSym.st_name, funcName) != 0){
while(1){
printf("hash:%x,nbucket:%d,funIndex:%d\n",dyn_hash,nbucket,funIndex);
lseek(fd, dyn_hash + 4 * (2 + nbucket + funIndex), SEEK_SET);
if(read(fd, &funIndex, 4) != 4){
puts("Read funIndex failed\n");
goto _error;
}
printf("funcIndex:%d\n", funIndex);
if(funIndex == 0){
puts("Cannot find funtion!\n");
goto _error;
}
lseek(fd, dyn_symtab + funIndex * sizeof(Elf32_Sym), SEEK_SET);
if(read(fd, &funSym, sizeof(Elf32_Sym)) != sizeof(Elf32_Sym)){
puts("In FOR loop, Read funSym failed");
goto _error;
}
if(strcmp(dynstr + funSym.st_name, funcName) == 0){
break;
}
}
}
printf("Find: %s, offset = 0x%x, size = 0x%x\n", funcName, funSym.st_value, funSym.st_size);
info->st_value = funSym.st_value;
info->st_size = funSym.st_size;
free(dynstr);
return 0;
_error:
free(dynstr);
return -1;
}
int main(int argc, char **argv){
char secName[] = ".text";
char funcName[] = "Java_com_example_shelldemo2_MainActivity_getString";
char *soName = "libdemo.so";
char *content = NULL;
int fd, i;
Elf32_Off secOff;
funcInfo info;
unsigned a = elfhash(funcName);
printf("a:%d\n", a);
fd = open(soName, O_RDWR);
if(fd < 0){
printf("open %s failed\n", argv[1]);
goto _error;
}
secOff = findTargetSectionAddr(fd, secName);
if(secOff == -1){
printf("Find section %s failed\n", secName);
goto _error;
}
if(getTargetFuncInfo(fd, funcName, &info) == -1){
printf("Find function %s failed\n", funcName);
goto _error;
}
content = (char*) malloc(info.st_size);
if(content == NULL){
puts("Malloc space failed");
goto _error;
}
//这里需要注意的info.st_value-1
lseek(fd, info.st_value - 1, SEEK_SET);
if(read(fd, content, info.st_size) != info.st_size){
puts("Malloc space failed");
goto _error;
}
for(i=0;i<info.st_size -1;i++){
content[i] = ~content[i];
}
lseek(fd, info.st_value-1, SEEK_SET);
if(write(fd, content, info.st_size) != info.st_size){
puts("Write modified content to .so failed");
goto _error;
}
puts("Complete!");
_error:
free(content);
close(fd);
return 0;
}

解密:书中的麻烦了,直接用指针函数就行。
参考http://xn--74q78i15hxv3arigm4e.cn/2018/06/29/android%E5%BA%94%E7%94%A8%E5%8A%A0%E5%9B%BA2/
修改导出:加载后,用符号表找到导出符号,修改其value。外部引用是先查符号表的。(不是看全局符号表?用时才加?如果查的是加载好的全局表应该改节无用)
修改导入:是改got表内的值。

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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <jni.h>
#include <android/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <elf.h>
#include <sys/mman.h>
#define DEBUG
typedef struct _funcInfo{
Elf32_Addr st_value;
Elf32_Word st_size;
}funcInfo;
void init_getString() __attribute__((constructor));
static void print_debug(const char *msg){
#ifdef DEBUG
__android_log_print(ANDROID_LOG_INFO, "JNITag", "%s", msg);
#endif
}
static unsigned elfhash(const char *_name)
{
const unsigned char *name = (const unsigned char *) _name;
unsigned h = 0, g;
while(*name) {
h = (h << 4) + *name++;
g = h & 0xf0000000;
h ^= g;
h ^= g >> 24;
}
return h;
}
static unsigned int getLibAddr(){
unsigned int ret = 0;
char name[] = "libdemo.so";
char buf[4096], *temp;
int pid;
FILE *fp;
pid = getpid();
sprintf(buf, "/proc/%d/maps", pid);
fp = fopen(buf, "r");
if(fp == NULL)
{
puts("open failed");
goto _error;
}
while(fgets(buf, sizeof(buf), fp)){
if(strstr(buf, name)){
temp = strtok(buf, "-");
ret = strtoul(temp, NULL, 16);
break;
}
}
_error:
fclose(fp);
return ret;
}
static char getTargetFuncInfo(unsigned long base, const char *funcName, funcInfo *info){
char flag = -1, *dynstr;
int i;
Elf32_Ehdr *ehdr;
Elf32_Phdr *phdr;
Elf32_Off dyn_vaddr;
Elf32_Word dyn_size, dyn_strsz;
Elf32_Dyn *dyn;
Elf32_Addr dyn_symtab, dyn_strtab, dyn_hash;
Elf32_Sym *funSym;
unsigned funHash, nbucket;
unsigned *bucket, *chain;
ehdr = (Elf32_Ehdr *)base;
phdr = (Elf32_Phdr *)(base + ehdr->e_phoff);
// __android_log_print(ANDROID_LOG_INFO, "JNITag", "phdr = 0x%p, size = 0x%x\n", phdr, ehdr->e_phnum);
for (i = 0; i < ehdr->e_phnum; ++i) {
// __android_log_print(ANDROID_LOG_INFO, "JNITag", "phdr = 0x%p\n", phdr);
if(phdr->p_type == PT_DYNAMIC){
flag = 0;
print_debug("Find .dynamic segment");
break;
}
phdr ++;
}
if(flag)
goto _error;
dyn_vaddr = phdr->p_vaddr + base;
dyn_size = phdr->p_filesz;
__android_log_print(ANDROID_LOG_INFO, "JNITag", "dyn_vadd = 0x%x, dyn_size = 0x%x", dyn_vaddr, dyn_size);
flag = 0;
for (i = 0; i < dyn_size / sizeof(Elf32_Dyn); ++i) {
dyn = (Elf32_Dyn *)(dyn_vaddr + i * sizeof(Elf32_Dyn));
if(dyn->d_tag == DT_SYMTAB){
dyn_symtab = (dyn->d_un).d_ptr;
flag += 1;
__android_log_print(ANDROID_LOG_INFO, "JNITag", "Find .dynsym section, addr = 0x%x\n", dyn_symtab);
}
if(dyn->d_tag == DT_HASH){
dyn_hash = (dyn->d_un).d_ptr;
flag += 2;
__android_log_print(ANDROID_LOG_INFO, "JNITag", "Find .hash section, addr = 0x%x\n", dyn_hash);
}
if(dyn->d_tag == DT_STRTAB){
dyn_strtab = (dyn->d_un).d_ptr;
flag += 4;
__android_log_print(ANDROID_LOG_INFO, "JNITag", "Find .dynstr section, addr = 0x%x\n", dyn_strtab);
}
if(dyn->d_tag == DT_STRSZ){
dyn_strsz = (dyn->d_un).d_val;
flag += 8;
__android_log_print(ANDROID_LOG_INFO, "JNITag", "Find strsz size = 0x%x\n", dyn_strsz);
}
}
if((flag & 0x0f) != 0x0f){
print_debug("Find needed .section failed\n");
goto _error;
}
dyn_symtab += base;
dyn_hash += base;
dyn_strtab += base;
dyn_strsz += base;
funHash = elfhash(funcName);
funSym = (Elf32_Sym *) dyn_symtab;
dynstr = (char*) dyn_strtab;
nbucket = *((int *) dyn_hash);
bucket = (int *)(dyn_hash + 8);
chain = (unsigned int *)(dyn_hash + 4 * (2 + nbucket));
flag = -1;
__android_log_print(ANDROID_LOG_INFO, "JNITag", "hash = 0x%x, nbucket = 0x%x\n", funHash, nbucket);
int mod = (funHash % nbucket);
__android_log_print(ANDROID_LOG_INFO, "JNITag", "mod = %d\n", mod);
__android_log_print(ANDROID_LOG_INFO, "JNITag", "i = 0x%d\n", bucket[mod]);
for(i = bucket[mod]; i != 0; i = chain[i]){
__android_log_print(ANDROID_LOG_INFO, "JNITag", "Find index = %d\n", i);
if(strcmp(dynstr + (funSym + i)->st_name, funcName) == 0){
flag = 0;
__android_log_print(ANDROID_LOG_INFO, "JNITag", "Find %s\n", funcName);
break;
}
}
if(flag) goto _error;
info->st_value = (funSym + i)->st_value;
info->st_size = (funSym + i)->st_size;
__android_log_print(ANDROID_LOG_INFO, "JNITag", "st_value = %d, st_size = %d", info->st_value, info->st_size);
return 0;
_error:
return -1;
}
void init_getString(){
const char target_fun[] = "Java_com_example_shelldemo2_MainActivity_getString";
funcInfo info;
int i;
unsigned int npage, base = getLibAddr();
__android_log_print(ANDROID_LOG_INFO, "JNITag", "base addr = 0x%x", base);
if(getTargetFuncInfo(base, target_fun, &info) == -1){
print_debug("Find Java_com_example_shelldemo2_MainActivity_getString failed");
return ;
}
npage = info.st_size / PAGE_SIZE + ((info.st_size % PAGE_SIZE == 0) ? 0 : 1);
__android_log_print(ANDROID_LOG_INFO, "JNITag", "npage = 0x%d", npage);
__android_log_print(ANDROID_LOG_INFO, "JNITag", "npage = 0x%d", PAGE_SIZE);
if(mprotect((void *) ((base + info.st_value) / PAGE_SIZE * PAGE_SIZE), 4096*npage, PROT_READ | PROT_EXEC | PROT_WRITE) != 0){
print_debug("mem privilege change failed");
}
for(i=0;i< info.st_size - 1; i++){
char *addr = (char*)(base + info.st_value -1 + i);
*addr = ~(*addr);
}
if(mprotect((void *) ((base + info.st_value) / PAGE_SIZE * PAGE_SIZE), 4096*npage, PROT_READ | PROT_EXEC) != 0){
print_debug("mem privilege change failed");
}
}
JNIEXPORT jstring JNICALL
Java_com_example_shelldemo2_MainActivity_getString( JNIEnv* env,
jobject thiz )
{
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#define ABI "armeabi-v7a/NEON"
#else
#define ABI "armeabi-v7a"
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#elif defined(__mips__)
#define ABI "mips"
#else
#define ABI "unknown"
#endif
return (*env)->NewStringUTF(env, "Native method return!");
}