首页
社区
课程
招聘
[原创]ELF最小加载器修复
发表于: 2025-11-27 16:21 821

[原创]ELF最小加载器修复

2025-11-27 16:21
821

基于对UPX加载分析所制

模拟内核对栈区布局

动态加载可执行文件


.global _start
.type _start, @function
.extern load
_start:
    mov	x0, sp // x0->argc
    ldr	x1, [x0],#8 // x0->argv
    add	x0, x0, w1, sxtw #3
    add	x0, x0, #0x8 // x0->envp
    envp:
    ldr	x1, [x0],#8
    cbnz	x1, envp
    bl load
    br x0

.global _svc
.type _svc, @function
_svc:
    mov x8, x0
    mov x0, x1
    mov x1, x2
    mov x2, x3
    mov x3, x4
    mov x4, x5
    mov x5, x6
    svc #0
    ret
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <elf.h>
extern "C" __u64 _svc(...);

#define __align_up(x)         ((x + 0x1000 - 1) & ~(0x1000 - 1))

#define _exit_group(sig) _svc(__NR_exit_group,sig)

#define _mprotect(addr,len,prot) _svc(__NR_mprotect,addr,len,prot)

#define _open(name,flag) _svc(__NR_openat,AT_FDCWD,name,flag)

#define _close(fd) _svc(__NR_close,fd)

#define _lseek(fd,offset,whence) _svc(__NR_lseek,fd,offset,whence)

#define _read(fd,buf,count) _svc(__NR_read,fd,buf,count)

#define _mmap(addr,length,prot,flags,fd,offset) _svc(__NR_mmap,addr,length,prot,flags,fd,offset)

#define _mremap(addr, old_size, new_size, flags) _svc(__NR_mremap, addr, old_size, new_size, flags)

#define _munmap(addr,length) _svc(__NR_munmap,addr,length)

static inline void _memcpy(void *dest,void *src,size_t n)
{
  for(int i = 0; i < n; i++)
  {
   *(char *)((uint64_t)dest + i) = *(char *)((uint64_t)src + i);
  }
}

static inline void _memset(void *dest,size_t n)
{
  for(int i = 0; i < n; i++)
  {
   *(char *)((uint64_t)dest + i) = 0;
  }
}
#include <svc.h>
__attribute__((section(".bss"))) Elf64_Phdr *Phdr; //段表指针
__attribute__((section(".bss"))) __u64 e_phnum; //条目数量
__attribute__((section(".bss"))) __u64 e_entry; //入口点

#ifdef __cplusplus
extern "C" {
#endif

 int elf_mmap(int fd)
 {
   int linker_fd;
   
   int size = _lseek(fd, 0, SEEK_END);
   
   _lseek(fd, 0, SEEK_SET);
   
   void *data = (void *)_mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, nullptr);
   
   void *ptr = (void *)_mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, nullptr, nullptr);
   
   Elf64_Ehdr *Ehdr = (Elf64_Ehdr *)data;
   
   Phdr = (Elf64_Phdr *)((__u64)data + Ehdr->e_phoff);
   
   for(int i = 0; i < Ehdr->e_phnum; i++)
   {
   
     if(__align_up(Phdr[i].p_vaddr + Phdr[i].p_memsz) > size)
     {
       ptr = (void *)_mremap(ptr,size,__align_up(Phdr[i].p_vaddr + Phdr[i].p_memsz),MREMAP_MAYMOVE);
       size = __align_up(Phdr[i].p_vaddr + Phdr[i].p_memsz);
     }
     
     _memcpy((void *)((__u64)ptr + Phdr[i].p_vaddr),(void *)((__u64)data + Phdr[i].p_offset),Phdr[i].p_filesz);
      
     if(Phdr[i].p_type == PT_INTERP)
     {
       linker_fd = _open((__u64)ptr + Phdr[i].p_vaddr, O_RDONLY);
     }
     
   }
   
   Phdr = (Elf64_Phdr *)((__u64)ptr + Ehdr->e_phoff);
   
   e_phnum = Ehdr->e_phnum;
   
   e_entry = (__u64)ptr + Ehdr->e_entry;
   
   _munmap(data,_lseek(fd, 0, SEEK_END));
   
   _close(fd);
   
    return linker_fd;
   
 }

 __u64 load(Elf64_auxv_t* auxv)
 {

   int linker_fd = elf_mmap(_open("/system/bin/sh",O_RDONLY)); //  /system/bin/sh  需要加载的文件
  
   int size = _lseek(linker_fd, 0, SEEK_END);

   Elf64_Ehdr *Ehdr = (Elf64_Ehdr *)_mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, linker_fd, nullptr);
   
   _close(linker_fd);
   
   for(int i = 0;auxv[i].a_type != 0;i++)
   {
      switch (auxv[i].a_type)
      {
        case AT_PHDR:
        auxv[i].a_un.a_val = (__u64)Phdr; //段表
        break;
       
        case AT_PHNUM:
        auxv[i].a_un.a_val = e_phnum; //段表条目数量
        break;
       
        case AT_BASE:
        auxv[i].a_un.a_val = (__u64)Ehdr; //链接器基地址
        break;
       
        case AT_ENTRY:
        auxv[i].a_un.a_val = e_entry; // 入口
        break;
       
        default:
        break;
      }
   }

   Phdr = (Elf64_Phdr *)((__u64)Ehdr + Ehdr->e_phoff);
   
   for(int i = 0; i < Ehdr->e_phnum; i++) //为动态链接器初始化
   {
     _memset((void *)((__u64)Ehdr + Phdr[i].p_vaddr + Phdr[i].p_filesz),Phdr[i].p_memsz - Phdr[i].p_filesz);
   }
   
   return (__u64)Ehdr + Ehdr->e_entry;
 }

#ifdef __cplusplus
}
#endif



传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2026-1-14 19:17 被CSProtect1.0编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 1507
活跃值: (3893)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
2

好玩,自己编译了一个android arm64的demo。感谢分享。增加了一个日志,方便调试。

#define _write(fd, buf, count) _svc(__NR_write, fd, buf, count)


static inline void debug_print(const char *str)

{   //自动求字符串长度

    size_t len= 0;

    const char*p=str;

    while (*p!='\0')

    {

        len++;

        p++;

    }

   

    // 使用 _write 宏:fd=2 (STDERR), buf=str, count=len

    _write(STDERR_FILENO, (void*)str, len);

}



最后于 2025-12-1 17:56 被iBa0编辑 ,原因:
2025-12-1 17:55
0
游客
登录 | 注册 方可回帖
返回