All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.unidbg.linux.LinuxModule Maven / Gradle / Ivy

There is a newer version: 0.9.8
Show newest version
package com.github.unidbg.linux;

import com.github.unidbg.Alignment;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.Symbol;
import com.github.unidbg.arm.ARM;
import com.github.unidbg.memory.MemRegion;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.pointer.UnidbgPointer;
import com.github.unidbg.spi.InitFunction;
import com.github.unidbg.spi.LibraryFile;
import com.github.unidbg.utils.Inspector;
import com.github.unidbg.virtualmodule.VirtualSymbol;
import com.sun.jna.Pointer;
import net.fornwall.jelf.ArmExIdx;
import net.fornwall.jelf.ElfDynamicStructure;
import net.fornwall.jelf.ElfException;
import net.fornwall.jelf.ElfFile;
import net.fornwall.jelf.ElfSection;
import net.fornwall.jelf.ElfSymbol;
import net.fornwall.jelf.GnuEhFrameHeader;
import net.fornwall.jelf.MemoizedObject;
import net.fornwall.jelf.SymbolLocator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class LinuxModule extends Module {

    private static final Log log = LogFactory.getLog(LinuxModule.class);

    static LinuxModule createVirtualModule(String name, final Map symbols, Emulator emulator) {
        if (symbols.isEmpty()) {
            throw new IllegalArgumentException("symbols is empty");
        }

        List list = new ArrayList<>(symbols.values());
        Collections.sort(list, new Comparator() {
            @Override
            public int compare(UnidbgPointer o1, UnidbgPointer o2) {
                return (int) (o1.peer - o2.peer);
            }
        });
        UnidbgPointer first = list.get(0);
        UnidbgPointer last = list.get(list.size() - 1);
        Alignment alignment = ARM.align(first.peer, last.peer - first.peer, emulator.getPageAlign());
        final long base = alignment.address;
        final long size = alignment.size;

        if (log.isDebugEnabled()) {
            log.debug("createVirtualModule first=0x" + Long.toHexString(first.peer) + ", last=0x" + Long.toHexString(last.peer) + ", base=0x" + Long.toHexString(base) + ", size=0x" + Long.toHexString(size));
        }

        LinuxModule module = new LinuxModule(base, size, name, null,
                Collections.emptyList(), Collections.emptyList(),
                Collections.emptyMap(), Collections.emptyList(),
                null, null, null, null, null, null) {
            @Override
            public Symbol findSymbolByName(String name, boolean withDependencies) {
                UnidbgPointer pointer = symbols.get(name);
                if (pointer != null) {
                    return new VirtualSymbol(name, this, pointer.peer);
                } else {
                    return null;
                }
            }
            @Override
            public ElfSymbol getELFSymbolByName(String name) {
                return null;
            }
            @Override
            public boolean isVirtual() {
                return true;
            }
        };
        for (Map.Entry entry : symbols.entrySet()) {
            module.registerSymbol(entry.getKey(), entry.getValue().peer);
        }
        return module;
    }

    private final SymbolLocator dynsym;
    private final List unresolvedSymbol;
    public final List initFunctionList;
    public final MemoizedObject armExIdx;
    public final MemoizedObject ehFrameHeader;
    private final ElfSection symbolTableSection;
    public final ElfFile elfFile;
    public final ElfDynamicStructure dynamicStructure;

    LinuxModule(long base, long size, String name, SymbolLocator dynsym,
                List unresolvedSymbol, List initFunctionList, Map neededLibraries, List regions,
                MemoizedObject armExIdx, MemoizedObject ehFrameHeader,
                ElfSection symbolTableSection, ElfFile elfFile, ElfDynamicStructure dynamicStructure, LibraryFile libraryFile) {
        super(name, base, size, neededLibraries, regions, libraryFile);

        this.dynsym = dynsym;
        this.unresolvedSymbol = unresolvedSymbol;
        this.initFunctionList = initFunctionList;
        this.armExIdx = armExIdx;
        this.ehFrameHeader = ehFrameHeader;
        this.symbolTableSection = symbolTableSection;
        this.elfFile = elfFile;
        this.dynamicStructure = dynamicStructure;
    }

    @Override
    public int virtualMemoryAddressToFileOffset(long offset) {
        try {
            return (int) elfFile.virtualMemoryAddrToFileOffset(offset);
        } catch (ElfException e) {
            return -1;
        } catch (IOException e) {
            throw new IllegalStateException("virtualMemoryAddressToFileOffset offset=0x" + Long.toHexString(offset));
        }
    }

    void callInitFunction(Emulator emulator, boolean mustCallInit) throws IOException {
        if (!mustCallInit && !unresolvedSymbol.isEmpty()) {
            for (ModuleSymbol moduleSymbol : unresolvedSymbol) {
                log.info("[" + name + "]" + moduleSymbol.getSymbol().getName() + " symbol is missing before init relocationAddr=" + moduleSymbol.getRelocationAddr());
            }
            return;
        }

        int index = 0;
        while (!initFunctionList.isEmpty()) {
            InitFunction initFunction = initFunctionList.remove(0);
            long initAddress = initFunction.getAddress();
            if (initFunctionListener != null) {
                initFunctionListener.onPreCallInitFunction(this, initAddress, index);
            }
            initAddress = initFunction.call(emulator);
            if (initFunctionListener != null) {
                initFunctionListener.onPostCallInitFunction(this, initAddress, index);
            }
            index++;
        }
    }

    public List getUnresolvedSymbol() {
        return unresolvedSymbol;
    }

    @Override
    public Symbol findSymbolByName(String name, boolean withDependencies) {
        try {
            ElfSymbol elfSymbol = dynsym.getELFSymbolByName(name);
            if (elfSymbol != null && !elfSymbol.isUndef()) {
                return new LinuxSymbol(this, elfSymbol);
            }

            if (withDependencies) {
                return findDependencySymbolByName(name);
            }
            return null;
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    public ElfSymbol getELFSymbolByName(String name) throws IOException {
        return dynsym.getELFSymbolByName(name);
    }

    @Override
    public Symbol findClosestSymbolByAddress(long addr, boolean fast) {
        try {
            long soaddr = addr - base;
            if (soaddr <= 0) {
                return null;
            }
            ElfSymbol elfSymbol = dynsym == null ? null : dynsym.getELFSymbolByAddr(soaddr);
            if (symbolTableSection != null && elfSymbol == null) {
                elfSymbol = symbolTableSection.getELFSymbolByAddr(soaddr);
            }
            Symbol symbol = null;
            if (elfSymbol != null) {
                symbol = new LinuxSymbol(this, elfSymbol);
            }
            long entry = base + entryPoint;
            if (addr >= entry && (symbol == null || entry > symbol.getAddress())) {
                symbol = new VirtualSymbol("start", this, entry);
            }
            return symbol;
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    @Override
    public int callEntry(Emulator emulator, String... args) {
        if (entryPoint <= 0) {
            throw new IllegalStateException("Invalid entry point");
        }

        Memory memory = emulator.getMemory();
        final UnidbgPointer stack = memory.allocateStack(0);

        int argc = 0;
        List argv = new ArrayList<>();

        argv.add(memory.writeStackString(emulator.getProcessName()));
        argc++;

        for (int i = 0; args != null && i < args.length; i++) {
            String arg = args[i];
            argv.add(memory.writeStackString(arg));
            argc++;
        }

        if (argc % 2 != 0) { // alignment sp
            memory.allocateStack(emulator.getPointerSize());
        }

        Pointer auxvPointer = memory.allocateStack(emulator.getPointerSize());
        assert auxvPointer != null;
        auxvPointer.setPointer(0, null);

        Pointer envPointer = memory.allocateStack(emulator.getPointerSize());
        assert envPointer != null;
        envPointer.setPointer(0, null);

        Pointer pointer = memory.allocateStack(emulator.getPointerSize());
        assert pointer != null;
        pointer.setPointer(0, null); // NULL-terminated argv

        Collections.reverse(argv);
        for (Pointer arg : argv) {
            pointer = memory.allocateStack(emulator.getPointerSize());
            assert pointer != null;
            pointer.setPointer(0, arg);
        }

        UnidbgPointer kernelArgumentBlock = memory.allocateStack(emulator.getPointerSize());
        assert kernelArgumentBlock != null;
        kernelArgumentBlock.setInt(0, argc);

        if (log.isDebugEnabled()) {
            UnidbgPointer sp = memory.allocateStack(0);
            byte[] data = sp.getByteArray(0, (int) (stack.peer - sp.peer));
            Inspector.inspect(data, "kernelArgumentBlock=" + kernelArgumentBlock + ", envPointer=" + envPointer + ", auxvPointer=" + auxvPointer);
        }

        return emulator.eEntry(base + entryPoint, kernelArgumentBlock.peer).intValue();
    }

    @Override
    public Number callFunction(Emulator emulator, long offset, Object... args) {
        return emulateFunction(emulator, base + offset, args);
    }

    @Override
    public String getPath() {
        return name;
    }

    final Map hookMap = new HashMap<>();

    @Override
    public void registerSymbol(String symbolName, long address) {
        hookMap.put(symbolName, address);
    }

    @Override
    public String toString() {
        return "LinuxModule{" +
                "base=0x" + Long.toHexString(base) +
                ", size=" + size +
                ", name='" + name + '\'' +
                '}';
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy