基于linker实现so加壳补充-------从dex中加载so

本文为看雪论坛优秀文章
看雪论坛作者ID:r0ysue
1
简介
2、实现libart.so中的inlinehook
3、hook dex加载函数更改只读权限
4、修正getsoinfo函数

2
so地址页对齐&多余数据
static main(void){auto fp, begin, end, dexbyte;fp = fopen("d:\\1.so", "wb");begin = 0x0000007366280000;end = begin + 0x0036000;for ( dexbyte = begin; dexbyte < end;dexbyte ++ ){fputc(Byte(dexbyte), fp);}}


搞定完这里,把so和插件dex都写入一个b.txt,然后直接用DexClassLoader加载起来就好,期间我模仿之前寒冰老师出的ctf题的写法,将b.txt搞到了资源目录然后使用的时候再复制到cache目录。
copyAssetAndWrite("b.txt",getApplicationContext());....DexClassLoader loader=new DexClassLoader(path,"/sdcard","/sdcard",context.getClassLoader());
3
实现libart.so中的inlinehook
4
寻找LoadMethod函数地址
char line[1024];int *startr;int *end;int n=1;FILE *fp=fopen("/proc/self/maps","r");while (fgets(line, sizeof(line), fp)) {//从maps种扫描libart.so的地址if (strstr(line, libname) ) {__android_log_print(6,"r0ysue","");if(n==1){startr = reinterpret_cast<int *>(strtoul(strtok(line, "-"), NULL, 16));end = reinterpret_cast<int *>(strtoul(strtok(NULL, " "), NULL, 16));}else{strtok(line, "-");end = reinterpret_cast<int *>(strtoul(strtok(NULL, " "), NULL, 16));}n++;}}size_t gnu_nbucket_ = 0;// skip symndxuint32_t gnu_maskwords_ = 0;uint32_t gnu_shift2_ =0;ElfW(Addr)* gnu_bloom_filter_= nullptr;uint32_t* gnu_bucket_ = nullptr;uint32_t* gnu_chain_ = nullptr;//导出表4项int phof=0;Elf64_Ehdr header;memcpy(&header,startr,sizeof(Elf64_Ehdr));uint64 rel= 0;size_t size=0;long* plt= nullptr;char* strtab_= nullptr;Elf64_Sym* symtab_= nullptr;Elf64_Phdr cc;memcpy (&cc,((char*)(startr)+header.e_phoff),sizeof(Elf64_Phdr));for(int y=0;y<header.e_phnum;y++){memcpy(&cc, (char *) (startr) +header.e_phoff+sizeof(Elf64_Phdr) * y, sizeof(Elf64_Phdr));if(cc.p_type==6) {//程序头偏移phof=cc.p_paddr-cc.p_offset;}}for(int y=0;y<header.e_phnum;y++){memcpy(&cc, (char *) (startr) +header.e_phoff+sizeof(Elf64_Phdr) * y, sizeof(Elf64_Phdr));if(cc.p_type==2) {//p_type=2代表找到了动态段Elf64_Dyn dd;for(y=0;y==0||dd.d_tag!=0;y++) {memcpy(&dd, (char *) (startr) + cc.p_offset + y * sizeof(Elf64_Dyn)+0x1000,sizeof(Elf64_Dyn));if(dd.d_tag==0x6ffffef5){//找到了 DT_GNU_HASH段也就是导出表gnu_nbucket_ = reinterpret_cast<uint32_t*>((char*)startr + dd.d_un.d_ptr-phof)[0];// skip symndxgnu_maskwords_ = reinterpret_cast<uint32_t*>((char*)startr + dd.d_un.d_ptr-phof)[2];gnu_shift2_ = reinterpret_cast<uint32_t*>((char*)startr + dd.d_un.d_ptr-phof)[3];gnu_bloom_filter_ = reinterpret_cast<ElfW(Addr)*>((char*)startr + dd.d_un.d_ptr + 16-phof);gnu_bucket_ = reinterpret_cast<uint32_t*>(gnu_bloom_filter_ + gnu_maskwords_);// amend chain for symndx = header[1]gnu_chain_ = reinterpret_cast<uint32_t *>( gnu_bucket_ +gnu_nbucket_-reinterpret_cast<uint32_t *>((char *) startr +dd.d_un.d_ptr-phof)[1]);}if(dd.d_tag==5 ){//得到字符串表的首地址strtab_=reinterpret_cast< char*>((char *) startr+dd.d_un.d_ptr-phof);}if(dd.d_tag==6 ){//得到符号表的首地址symtab_= reinterpret_cast<Elf64_Sym *>(((char *) startr + dd.d_un.d_ptr-phof));}}}}
char* name_=symname;uint32_t h = 5381;const uint8_t* name = reinterpret_cast<const uint8_t*>(name_);while (*name != 0) {h += (h << 5) + *name++; // h*33 + c = h + h * 32 + c = h + h << 5 + c}//实现symbol_name.gnu_hashint index=0;uint32_t h2 = h >> gnu_shift2_;uint32_t bloom_mask_bits = sizeof(ElfW(Addr))*8;uint32_t word_num = (h / bloom_mask_bits) & gnu_maskwords_;ElfW(Addr) bloom_word = gnu_bloom_filter_[word_num];n = gnu_bucket_[h % gnu_nbucket_];//模仿安卓源码直接抄do {Elf64_Sym * s = symtab_ + n;char * sb=strtab_+ s->st_name;if (strcmp(sb ,reinterpret_cast<const char *>(name_)) == 0 ) {break;}} while ((gnu_chain_[n++] & 1) == 0);
void* mysym=(char *)startr+sb->st_value-phof5
粗略的实现inline hook
1、首先构想一个整体的思路,如何实现每个我们需要hook的函数都能跳转到我们自己的函数执行?
这个问题可以用一条指令就是b一个地址,但是又有一个问题,这个地址是有范围要求的,如果不在同一个so当中很难满足这个界限要求,这一点在https://armconverter.com/ 中可以得到验证,所以这种方式是不可以的。
int s=0;for(n=0;*(int*)((char *)startr+sb->st_value-phof+n)!=0xd65f03c0;n=n+4){int code=*(int*)((char *)startr+sb->st_value-phof+n);if(code>>32==0xa9&&(code&0xfff)==0xbfd){__android_log_print(6,"r0ysue","%x",n);s=1;break;}}if(s=1){n=n+4;}else{n=0;}one= *(int*)((char *)startr+sb->st_value-phof+n);two= *(int*)((char *)startr+sb->st_value-phof+n+4);three[ns=*(int*)((char *)startr+sb->st_value-phof+n+8);four[]=*(int*)((char *)startr+sb->st_value-phof+n+12);*(int*)((char *)startr+sb->st_value-phof+n)=0x58000051;//*(int*)((char *)startr+sb->st_value-phof+n+4)=0xd63f0220;*(long**)((char *)startr+sb->st_value-phof+n+8)= reinterpret_cast<long*>(myloadmethod);//自己函数的地址

void __attribute((naked)) myloadmethod(){asm("add x30,x30,8");//指定跳回去的位置asm("sub SP, SP, #0x100");//申请栈asm("stp X29, X30, [SP,#0x10]");//保护寄存器asm("stp X0, X1, [SP,#0x20]");asm("stp X2, X3, [SP,#0x30]");asm("stp X4, X5, [SP,#0x40]");asm("stp X6, X7, [SP,#0x50]");asm("stp X8, X9, [SP,#0x60]");asm("stp X10, X11, [SP,#0x70]");asm("stp X12, X13, [SP,#0x80]");asm("stp X14, X15, [SP,#0x90]");asm("ldp X16, X17, [SP,#0x10]");//保存x30到x17,当然这里用mov或者ldr都行我复制粘贴省事了asm("mov X16,SP");//这里参数处理我们想好就先用栈替代asm("mov x0,x0");//占位,会改成BL _Z4pltsv,也就是我们自己写的第二个函数asm("ldp X8, X9, [SP,#0x60]");//寄存器恢复asm("ldp X10, X11, [SP,#0x70]");asm("ldp X12, X13, [SP,#0x80]");asm("ldp X14, X15, [SP,#0x90]");asm("ldp X0, X1, [SP,#0x20]");asm("ldp X2, X3, [SP,#0x30]");asm("ldp X4, X5, [SP,#0x40]");asm("ldp X6, X7, [SP,#0x50]");asm("ldp X29, X30, [SP,#0x10]");asm("add SP, SP, #0x100");asm("mov x0,x0");//之前在原函数中占位的第1条指令asm("mov x0,x0");//之前在原函数中占位的第2条指令asm("mov x0,x0");//之前在原函数中占位的第3条指令asm("mov x0,x0");//之前在原函数中占位的第4条指令asm("RET");}
int code;if((long)myloadmethod>(long)plts){int off=(long)myloadmethod-(long)plts+48;code=0x97ffffff-off/4;}else{int off=(long)plts-(long)myloadmethod-48;code=off/4|0x94000000;}*(int*)((char *)myloadmethod+52)= reinterpret_cast<int>(code);
1、执行我们在外面传入的hook函数
2、恢复占用的指令
void plts(){func st=(func)fc;st();memcpy((char*)myloadmethod+0x60,&one,4);memcpy((char*)myloadmethod+0x64,&two,4);memcpy((char*)myloadmethod+0x68,&three,4);memcpy((char*)myloadmethod+0x6c,&four,4);}
one[ns]= *(int*)((char *)startr+sb->st_value-phof+n);two[ns]= *(int*)((char *)startr+sb->st_value-phof+n+4);three[ns]=*(int*)((char *)startr+sb->st_value-phof+n+8);four[ns]=*(int*)((char *)startr+sb->st_value-phof+n+12);funtab[ns]= reinterpret_cast<long>((char *) startr + sb->st_value - phof);ns++;
void plts(){unsigned long addr=0;int uu;__asm__("mov %[input_n], x17\r\n":[result_m] "=r" (addr):[input_n] "r" (addr));int yy=0;for(yy=0;yy<ns;yy++){if(addr-(unsigned long)funtab[yy]<0x100){break;}}func st=(func)fc[yy];st();memcpy((char*)myloadmethod+0x60,&one[yy],4);memcpy((char*)myloadmethod+0x64,&two[yy],4);memcpy((char*)myloadmethod+0x68,&three[yy],4);memcpy((char*)myloadmethod+0x6c,&four[yy],4);__android_log_print(6,"r0ysue","");}
void io(void* a,void*b){long** dex= static_cast<long **>(b);size= reinterpret_cast<size_t>(*(dex + 2));long* begin=(*(dex+1));if(size==0x392000&&fl==0) {//是我们自己大小的dex而且只取一次fl=1;realel= reinterpret_cast<long*>(begin );//拿到真正的dex地址jiake();//释放so,加壳函数上篇文章讲过了,所以这里不再赘述,只需注意修正got表中的变量的值即可}}void _init(){mainfun("_ZN3art11ClassLinker10LoadMethodERKNS_7DexFileERKNS_21ClassDataItemIteratorENS_6HandleINS_6mirror5ClassEEEPNS_9ArtMethodE", "libart.so",reinterpret_cast<void *>(io));}
6
hook dex加载函数更改只读权限
void jjj(void* a,void* b,int c,int d){d=7;__asm__("str %[input_n], [X16,#0x30]\r\n"//用到了刚才保存的寄存器,这里直接用:[result_m] "=r" (d):[input_n] "r" (d));}mainfun("_ZN3art6MemMap16MapFileAtAddressEPhmiiilbbPKcPNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEE", "libart.so",reinterpret_cast<void *>(jjj));
7
修正getsoinfo函数

static soinfo* soinfo_from_handle(void* handle) {if ((reinterpret_cast<uintptr_t>(handle) & 1) != 0) {auto it = g_soinfo_handles_map.find(reinterpret_cast<uintptr_t>(handle));if (it == g_soinfo_handles_map.end()) {return nullptr;} else {return it->second;}}
1、首先取了dl_g_soinfo_handles_map的值
2、然后将其中的值与他后面一个字节取余操作
3、取上一步结果乘8然后取首先取了dl_g_soinfo_handles_map的值中的值加这个偏移
4、取2次地址中的值并且加0x18
5、最后再取一次它其中地址的值就是soninfo指针了
.text:000000000000CC5C ADRP X12, #__dl_g_soinfo_handles_map_ptr@PAGE.text:000000000000CC60 LDR X12, [X12,#__dl_g_soinfo_handles_map_ptr@PAGEOFF].text:000000000000CC64 LDR X8, [X12,#(qword_FA468 - 0xFA460)].text:000000000000CC68 CBZ X8, loc_CCF4.text:000000000000CC6C SUB X9, X8, #1.text:000000000000CC70 AND X10, X9, X8.text:000000000000CC74 CBZ X10, loc_CC90.text:000000000000CC78 MOV X11, X19.text:000000000000CC7C CMP X8, X19.text:000000000000CC80 B.HI loc_CC94.text:000000000000CC84 UDIV X11, X19, X8.text:000000000000CC88 MSUB X11, X11, X8, X19.text:000000000000CC8C B loc_CC94.text:000000000000CC90 ; ---------------------------------------------------------------------------.text:000000000000CC90.text:000000000000CC90 loc_CC90 ; CODE XREF: __dl__Z10do_dlclosePv+5C↑j.text:000000000000CC90 AND X11, X9, X19.text:000000000000CC94.text:000000000000CC94 loc_CC94 ; CODE XREF: __dl__Z10do_dlclosePv+68↑j.text:000000000000CC94 ; __dl__Z10do_dlclosePv+74↑j.text:000000000000CC94 LDR X12, [X12].text:000000000000CC98 LDR X12, [X12,X11,LSL#3].text:000000000000CC9C CBZ X12, loc_CCF4.text:000000000000CCA0.text:000000000000CCA0 loc_CCA0 ; CODE XREF: __dl__Z10do_dlclosePv+A4↓j.text:000000000000CCA0 ; __dl__Z10do_dlclosePv+CC↓j.text:000000000000CCA0 LDR X12, [X12].text:000000000000CCA4 CBZ X12, loc_CCF4.text:000000000000CCA8 LDR X13, [X12,#8].text:000000000000CCAC CMP X13, X19.text:000000000000CCB0 B.NE loc_CCC4.text:000000000000CCB4 LDR X13, [X12,#0x10].text:000000000000CCB8 CMP X13, X19.text:000000000000CCBC B.NE loc_CCA0.text:000000000000CCC0 B loc_CCEC.text:000000000000CCC4 ; ---------------------------------------------------------------------------.text:000000000000CCC4.text:000000000000CCC4 loc_CCC4 ; CODE XREF: __dl__Z10do_dlclosePv+98↑j.text:000000000000CCC4 CBZ X10, loc_CCDC.text:000000000000CCC8 CMP X13, X8.text:000000000000CCCC B.CC loc_CCE0.text:000000000000CCD0 UDIV X14, X13, X8.text:000000000000CCD4 MSUB X13, X14, X8, X13.text:000000000000CCD8 B loc_CCE0.text:000000000000CCDC ; ---------------------------------------------------------------------------.text:000000000000CCDC.text:000000000000CCDC loc_CCDC ; CODE XREF: __dl__Z10do_dlclosePv:loc_CCC4↑j.text:000000000000CCDC AND X13, X13, X9.text:000000000000CCE0.text:000000000000CCE0 loc_CCE0 ; CODE XREF: __dl__Z10do_dlclosePv+B4↑j.text:000000000000CCE0 ; __dl__Z10do_dlclosePv+C0↑j.text:000000000000CCE0 CMP X13, X11.text:000000000000CCE4 B.EQ loc_CCA0.text:000000000000CCE8 B loc_CCF4.text:000000000000CCEC ; ---------------------------------------------------------------------------.text:000000000000CCEC.text:000000000000CCEC loc_CCEC ; CODE XREF: __dl__Z10do_dlclosePv+A8↑j.text:000000000000CCEC LDR X0, [X12,#0x18].text:000000000000CCF0 CBNZ X0, loc_CC50
void* nmm=(char*)startr+realoff;char *next=(char*)nmm+8;unsigned long map= reinterpret_cast<unsigned long>(strstr);unsigned long mapnext=*next;mapnext=map%mapnext;nmm=(long*)((char*)(*(long*)nmm)+mapnext*8);long* final= reinterpret_cast<long *>((char *) (**(long **) nmm) + 0x18);void* soinfo= reinterpret_cast<void *>(*final);return static_cast<uint64 *>(soinfo);

int fd;void *start;struct stat sb;fd = open("/system/bin/linker64", O_RDONLY); /*打开/etc/passwd */fstat(fd, &sb); /* 取得文件大小 */start = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);__android_log_print(6, "r0ysue", "%p", start);Elf64_Ehdr header;memcpy(&header, start, sizeof(Elf64_Ehdr));int secoff = header.e_shoff;int secsize = header.e_shentsize;int secnum = header.e_shnum;int secstr = header.e_shstrndx;Elf64_Shdr strtab;memcpy(&strtab, (char *) start + secoff + secstr * secsize, sizeof(Elf64_Shdr));int strtaboff = strtab.sh_offset;char strtabchar[strtab.sh_size];memcpy(&strtabchar, (char *) start + strtaboff, strtab.sh_size);Elf64_Shdr enumsec;int gotoff = 0;int gotsize = 0;int strtabsize = 0;int stroff = 0;for (int n = 0; n < secnum; n++) {memcpy(&enumsec, (char *) start + secoff + n * secsize, sizeof(Elf64_Shdr));if (strcmp(&strtabchar[enumsec.sh_name], ".symtab") == 0) {gotoff = enumsec.sh_offset;gotsize = enumsec.sh_size;__android_log_print(6, "r0ysue", "%x", gotsize);}if (strcmp(&strtabchar[enumsec.sh_name], ".strtab") == 0) {stroff = enumsec.sh_offset;strtabsize = enumsec.sh_size;__android_log_print(6, "r0ysue", "%x", stroff);}}int realoff=0;char relstr[strtabsize];Elf64_Sym tmp;memcpy(&relstr, (char *) start + stroff, strtabsize);for (int n = 0; n < gotsize; n = n + sizeof(Elf64_Sym)) {memcpy(&tmp, (char *)start + gotoff+n, sizeof(Elf64_Sym));if(tmp.st_name!=0&&strstr(relstr+tmp.st_name,"soinfo_handles_map"))realoff=tmp.st_value;}
8
总结
看雪ID:r0ysue
https://bbs.pediy.com/user-home-799845.htm

# 往期推荐
2.Android APP漏洞之战——Content Provider漏洞详解


球分享

球点赞

球在看

点击“阅读原文”,了解更多!
[广告]赞助链接:
关注数据与安全,洞悉企业级服务市场:https://www.ijiandao.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注KnowSafe微信公众号随时掌握互联网精彩
- MediaGo无需抓包,即可轻松嗅探视频资源
- 国产编程语言MoonBit正式被Github收录!两年核心用户数突破3万
- DramasQ:追剧新天地,带你畅游亚洲影视海洋
- 在Z|微步在线(北上广深等多省市)诚招大客户销售经理、行业leader、区域leader
- 在看 | “国防七校”西北工业大学遭受境外网络攻击
- GitHub:黑客盗用 OAuth 令牌,导致数十个组织数据泄露
- 生于俄罗斯的 Web 服务器王者 Nginx,现宣布俄罗斯禁止贡献!
- 消灭碎片化,Android 内核开发采取“上游优先”策略!
- 移动办公时代,我们究竟需要一台怎样的电脑?
- 2021版Java知识体系详解!(赠视频)
- 什么?print 函数还可以打印彩色围棋局面?
- 终于宣判了,疫情终究不是侵犯隐私的保护伞
赞助链接




