首页 > 其他分享 >so加固之手动脱upx

so加固之手动脱upx

时间:2023-02-01 17:55:51浏览次数:48  
标签:ImageBase address Program fd upx Dword 加固 so phoff

ELF可执行文件脱壳

使用upx对ELF文件进行加壳,加壳后的文件不包含动态链接信息,也就是说加壳后的可执行文件是一个纯静态链接文件。对于纯静态链接的可执行文件而言,linux内核在将此elf文件加载到内存后会直接修改应用层入口为此elf文件的入口函数,不再需要动态链接器的参与。

加壳后的elf文件的壳入口就是upx的壳代码,这部分代码会申请内存并保存原elf文件压缩的数据和upx壳的解压缩代码。加壳elf文件的入口函数执行完之后就会跳转到upx壳的解压缩代码中,解压缩代码会将压缩的数据解密并map到默认映射地址空间中。紧接着壳代码还会加载原elf文件的链接器程序并设置好对应的参数跳转到链接器程序的入口地址,这部分工作本来是由linux内核代码完成的。

当运行到linker入口时就可以对so内存地址空间进行dump,因为此时linker程序还未运行,也就是原elf文件的重定位信息并没有被其修改,所以dump时不需要对重定位数据进行修复。对于elf文件而言section信息不会被加载到内存所以可以直接清空。(idc脚本)

//获取基地址
ImageBase = AskAddr(0, "请输入基地址");
Message("ImageBase is :%x\n", ImageBase);
auto filename = AskFile(1, "*", "dump文件另存为");
Message("dump file :%s\n", filename);
auto fd = fopen(filename,"wb");
if(fd != 0)
{
        e_phoff=ImageBase+Dword(ImageBase+0x1C);
        e_phnum=Word(ImageBase+0x2C);
               
	//WriteFile PT_LOAD
        auto i;
        for(i = 0; i < e_phnum; i++)
        {
                if (Dword(e_phoff)==PT_LOAD )//PT_LOAD类型的会加载到内存中
                {
                        Program_Fileoffset=Dword(e_phoff+0x4);	                        //file offset
                        Program_start_address=ImageBase + Dword(e_phoff+0x8);	        //virtual address
                        Program_end_address=Program_start_address+Dword(e_phoff+0x14);	//结束地址                          
                        WriteFile(fd,Program_start_address,Program_end_address,Program_Fileoffset);            
                }
                e_phoff=e_phoff+0x20;
        }
        
        //将SHT(section header table)信息清除
        fseek(fd,0x30,0);
        fputc(0x00,fd);
        fputc(0x00,fd);
      
        fseek(fd,0x20,0);
        fputc(0x00,fd);
        fputc(0x00,fd);
        fputc(0x00,fd);
        fputc(0x00,fd);
        fclose(fd);
}

android so库文件脱壳

android so库文件也是标准的elf文件格式,但是与elf可执行文件的upx脱壳区别很大。因为so文件再被linker链接器加载后会被重定位,所以在dump时需要对重定位数据进行修复。

    //修复R_ARM_RELATIVE类型的重定位信息。
    currentaddr = rel_dyn_startaddr;
    e_phoff = ImageBase+Dword(ImageBase+0x1C);
    while(Dword(currentaddr + 4) == R_ARM_RELATIVE)
    {
        e_phoff = ImageBase + Dword(ImageBase + 0x1C);
        Elf32_Rel_offset = Dword(currentaddr);
        Elf32_Rel_address = ImageBase + Dword(currentaddr);

        //获得对应的.got表项的文件偏移
        for (i = 0; i < e_phnum; i++) {
            if (Dword(e_phoff) == PT_LOAD)//PT_LOAD类型的会加载到内存中
            {
                Program_Fileoffset = Dword(e_phoff + 0x4);                            //file offset
                Program_start_address = ImageBase + Dword(e_phoff + 0x8);             //virtual address
                Program_end_address = Program_start_address + Dword(e_phoff + 0x14);  //结束地址
                if ((Elf32_Rel_address >= Program_start_address) && (Elf32_Rel_address <= Program_end_address)) {
                    Elf32_Rel_fileOffset = Program_Fileoffset + (Elf32_Rel_address - Program_start_address);
                    //获得文件偏移后设置文件指针
                    fseek(fd, Elf32_Rel_fileOffset, 0);
                    Message(" Elf32_Rel_address= 0x%x\n", Elf32_Rel_address);
                }
            }
            e_phoff = e_phoff + 0x20;
        }


        //开始写入数据(修复.got表)
        writeByte = (Dword(Elf32_Rel_offset + ImageBase) - ImageBase) & 0x000000FF;
        fputc(writeByte, fd);
        Message("writeByte = 0x%x\n", writeByte);

        writeByte = ((Dword(Elf32_Rel_offset + ImageBase) - ImageBase) & 0x0000FF00) >> 8;
        fputc(writeByte, fd);
        Message("writeByte = 0x%x\n", writeByte);

        writeByte = ((Dword(Elf32_Rel_offset + ImageBase) - ImageBase) & 0x00FF0000) >> 16;
        fputc(writeByte, fd);
        Message("writeByte = 0x%x\n", writeByte);

        writeByte = ((Dword(Elf32_Rel_offset + ImageBase) - ImageBase) & 0xFF000000) >> 24;
        fputc(writeByte, fd);
        Message("writeByte = 0x%x\n", writeByte);

        currentaddr = currentaddr + Elf32_Rel_size;
    }

同时因为android 7之后增加了ELF section header检查,所以在抹去了section后程序是无法正常运行的,但是就静态分析而言是完全没问题的。下图就是利用idc脚本手动脱壳并去除了section信息后的程序。

标签:ImageBase,address,Program,fd,upx,Dword,加固,so,phoff
From: https://www.cnblogs.com/revercc/p/17083716.html

相关文章

  • 冒泡排序(Bubble Sort)
    一、算法概述1.1算法分类十种常见排序算法可以分为两大类:比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排......
  • 选择排序(Selection Sort)
    一、算法概述1.1算法分类十种常见排序算法可以分为两大类:比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排......
  • 插入排序(Insertion Sort)
    一、算法概述1.1算法分类十种常见排序算法可以分为两大类:比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排......
  • json .net 反序列化
    引用链接https://www.cnblogs.com/nice0e3/p/15294585.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%94%BB%E5%87%BBhttps://www.anquanke.com/post/id/172920#h3-3j......
  • Solidity极简入门#7. 映射类型
    这一讲,我们将介绍solidity中的哈希表:映射(Mapping)类型。映射Mapping在映射中,人们可以通过键(Key)来查询对应的值(Value),比如:通过一个人的id来查询他的钱包地址。声明映射的格式为......
  • Solidity极简入门#8. 变量初始值
    变量初始值在solidity中,声明但没赋值的变量都有它的初始值或默认值。这一讲,我们将介绍常用变量的初始值。值类型初始值boolean:falsestring:""int:0uint:0enum:枚举中......
  • [42S01] [Microsoft][SQL Server Native Client 11.0][SQL Server]数据库中已存在名为
    SQL server 下图中两个红色的地方不能保持一样,否则就会出现上面的错误 在 CONSTRAINT的后面表名中加上一些标识便可 (例_PK)与上面创建的表名区分开就可以了......
  • 书城9 - 前后端 json 数据的交互
    解析请求中的json数据,返回json数据1.加入Gson.jar包2.通过输入流读取数据,使用Gson对象解析字符串protectedvoidrequestBodyJSON(HttpServletRequestrequ......
  • springboot+webSocket
    1、新建WebSocketConfig配置类packagecom.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configurat......
  • Net6/SuperSocket通过命令和命令过滤器实现服务端/客户端双工通信
    十年河东,十年河西,莫欺少年穷学无止境,精益求精和上一节一致,通信数据结构如下:///+-------+---+-------------------------------+///|request|l|......