Revision: 2004
Author:
kit...@gmail.com
Date: Wed Sep 11 14:27:18 2013 UTC
Log: Analyzing kernels code pages almost done. Some minor changes and
cleanup neccessary
http://code.google.com/p/insight-vmi/source/detail?r=2004
Modified:
/trunk/libinsight/detect.cpp
/trunk/libinsight/include/insight/detect.h
=======================================
--- /trunk/libinsight/detect.cpp Fri Jul 12 14:13:15 2013 UTC
+++ /trunk/libinsight/detect.cpp Wed Sep 11 14:27:18 2013 UTC
@@ -10,16 +10,27 @@
#include <QRegExp>
#include <QProcess>
+#include <QHash>
+#include <QDir>
+#include <QDirIterator>
+
+#include <errno.h>
+
#include <limits>
-#define PAGE_SIZE 4096
+#define MODULE_PAGE_SIZE 4096
+#define KERNEL_CODEPAGE_SIZE 2097152
+
+#define
MODULE_BASE_DIR "/local-home/kittel/projekte/insight/images/symbols/ubuntu-13.04-64-server/3.8.13-19-generic-dbg"
+#define
KERNEL_IMAGE "/local-home/kittel/projekte/insight/images/symbols/ubuntu-13.04-64-server/linux-3.8.0/vmlinux"
+#define MEM_SAVE_DIR "/local-home/kittel/projekte/insight/memdump/"
QMultiHash<quint64, Detect::ExecutablePage> *Detect::ExecutablePages = 0;
Detect::Detect(KernelSymbols &sym) :
_kernel_code_begin(0), _kernel_code_end(0), _kernel_data_exec_end(0),
- _vsyscall_page(0), ExecutableSections(0), Functions(0), _sym(sym),
- _current_index(0)
+ _vsyscall_page(0), Functions(0),
+ _sym(sym), _current_index(0)
{
// Get data from System.map
_kernel_code_begin = _sym.memSpecs().systemMap.value("_text").address;
@@ -38,69 +49,1649 @@
}
}
-void Detect::getExecutableSections(QString file)
+#define GENERIC_NOP1 0x90
+
+#define P6_NOP1 GENERIC_NOP1
+#define P6_NOP2 0x66,0x90
+#define P6_NOP3 0x0f,0x1f,0x00
+#define P6_NOP4 0x0f,0x1f,0x40,0
+#define P6_NOP5 0x0f,0x1f,0x44,0x00,0
+#define P6_NOP6 0x66,0x0f,0x1f,0x44,0x00,0
+#define P6_NOP7 0x0f,0x1f,0x80,0,0,0,0
+#define P6_NOP8 0x0f,0x1f,0x84,0x00,0,0,0,0
+#define P6_NOP5_ATOMIC P6_NOP5
+
+#define ASM_NOP_MAX 8
+
+static const unsigned char p6nops[] =
{
- QProcess helper;
+ P6_NOP1,
+ P6_NOP2,
+ P6_NOP3,
+ P6_NOP4,
+ P6_NOP5,
+ P6_NOP6,
+ P6_NOP7,
+ P6_NOP8,
+ P6_NOP5_ATOMIC
+};
- // Regex
- int pos = 0;
- QRegExp
regex("\\s*\\[\\s*[0-9]{1,2}\\]\\s*([\\.a-zA-Z0-9_-]+)\\s*[A-Za-z]+\\s*([0-9A-Fa-f]+)"
- "\\s*([0-9A-Fa-f]+)\\s*([0-9A-Fa-f]+)",
Qt::CaseInsensitive);
+static const unsigned char * const p6_nops[ASM_NOP_MAX+2] =
+{
+ NULL,
+ p6nops,
+ p6nops + 1,
+ p6nops + 1 + 2,
+ p6nops + 1 + 2 + 3,
+ p6nops + 1 + 2 + 3 + 4,
+ p6nops + 1 + 2 + 3 + 4 + 5,
+ p6nops + 1 + 2 + 3 + 4 + 5 + 6,
+ p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
+ p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
+};
- // Free old data
- if (ExecutableSections != 0)
- delete(ExecutableSections);
- // Create HashMap
- ExecutableSections = new QMultiHash<QString, ExecutableSection>();
+//TODO Use QT Types
+struct alt_instr {
+ qint32 instr_offset; /* original instruction */
+ qint32 repl_offset; /* offset to replacement instruction */
+ quint16 cpuid; /* cpuid bit set for replacement */
+ quint8 instrlen; /* length of original instruction */
+ quint8 replacementlen; /* length of new instruction, <=
instrlen */
+};
- // Get Executable Sections
- helper.start("/bin/bash -c \"readelf -a " + file + " | grep -B1
\\\"AX\\\"");
- helper.waitForFinished();
+struct paravirt_patch_site {
+ quint8 *instr; /* original instructions */
+ quint8 instrtype; /* type of this instruction */
+ quint8 len; /* length of original instruction */
+ quint16 clobbers; /* what registers you may clobber */
+};
- QString output(helper.readAll());
+struct static_key {
+ quint32 enabled;
+};
- // Open file
- QFile f(file);
+struct jump_entry {
+ quint64 code;
+ quint64 target;
+ quint64 key;
+};
- if (!f.open(QIODevice::ReadOnly))
+struct tracepoint_func {
+ void *func;
+ void *data;
+};
+
+struct tracepoint {
+ const char *name; /* Tracepoint name */
+ struct static_key key;
+ void (*regfunc)(void);
+ void (*unregfunc)(void);
+ struct tracepoint_func *funcs;
+};
+
+PageVerifier::PageVerifier(const KernelSymbols &sym) :
+ _sym(sym), _current_index(0), ParsedExecutables(0), _symTable(),
_jumpEntries()
+{
+ ParsedExecutables = new QMultiHash<QString, elfParseData>();
+ _vmem = _sym.memDumps().at(_current_index)->vmem();
+
+ //TODO Find correct nops =>
http://lxr.free-electrons.com/source/arch/x86/kernel/alternative.c#L230
+ ideal_nops = p6_nops;
+}
+
+/**
+ * Find the file containing the module in elf format
+ */
+
+QString PageVerifier::findModuleFile(QString moduleName)
+{
+ moduleName = moduleName.trimmed();
+
+ //Some Filenames are not exactly the modulename. This is currently
cheating but ok :-)
+ if (moduleName == "kvm_intel") moduleName = QString("kvm-intel");
+ if (moduleName == "i2c_piix4") moduleName = QString("i2c-piix4");
+
+ //TODO get basedir from config or parameter
+ QString baseDirName = QString(MODULE_BASE_DIR);
+
+ QDirIterator dirIt(baseDirName,QDirIterator::Subdirectories);
+ while (dirIt.hasNext()) {
+ dirIt.next();
+ if (QFileInfo(dirIt.filePath()).isFile())
+ {
+ if (QFileInfo(dirIt.filePath()).suffix() == "ko" &&
QFileInfo(dirIt.filePath()).baseName() == moduleName)
+ {
+ //Console::out() << moduleName << ": " <<
QFileInfo(dirIt.filePath()).baseName() << "\n" << endl;
+ return dirIt.filePath();
+ }
+ }
+ }
+
+ debugerr("" << moduleName << " Kernelmodule not found!");
+ return QString("");
+}
+
+/**
+ * Read a File to Memory
+ * Important: The buffer must be freed after it was used!
+ */
+char* PageVerifier::readFile(QString fileName){
+ char *source = NULL;
+ FILE *fp = fopen(fileName.toStdString().c_str(), "r+b");
+ if (fp != NULL) {
+ /* Go to the end of the file. */
+ if (fseek(fp, 0L, SEEK_END) == 0) {
+ /* Get the size of the file. */
+ long bufsize = ftell(fp);
+ if (bufsize == -1) { /* Error */ }
+
+ /* Allocate our buffer to that size. */
+ source = (char *)malloc(sizeof(char) * (bufsize + 1));
+
+ /* Go back to the start of the file. */
+ if (fseek(fp, 0L, SEEK_SET) == 0) { /* Error */ }
+
+ /* Read the entire file into memory. */
+ size_t newLen = fread(source, sizeof(char), bufsize, fp);
+ if (newLen == 0) {
+ debugerr("Error reading file");
+ } else {
+ source[++newLen] = '\0'; /* Just to be safe. */
+ }
+ }
+ fclose(fp);
+ }
+
+ return source;
+}
+
+void PageVerifier::writeSectionToFile(QString moduleName, quint32
sectionNumber, QByteArray data){
+ //MEM_SAVE_DIR
+
+ QString fileName = QString(MEM_SAVE_DIR).append(moduleName)
+ .append(QString::number(sectionNumber));
+ //Console::out() << "Filename:" << fileName << " Segment: " <<
QString::number(sectionNumber) << endl;
+ QFile file( fileName );
+ if ( file.open(QIODevice::ReadWrite) )
{
- debugerr("Could not open file " << file << "!");
- return;
+ QDataStream stream( &file );
+ stream.writeRawData(data.data(), data.size());
+ file.close();
}
+}
- // Extract data
- while ((pos = regex.indexIn(output, pos)) != -1)
+void PageVerifier::writeModuleToFile(QString origFileName, Instance
currentModule, char * buffer ){
+ //MEM_SAVE_DIR
+
+ quint32 size = 0;
+ //get original file size
+ QFile origMod(origFileName);
+ if (origMod.open(QIODevice::ReadOnly)){
+ size = origMod.size();
+ }
+
+ QString fileName =
QString(MEM_SAVE_DIR).append(currentModule.member("name").toString().remove(QChar('"'),
Qt::CaseInsensitive))
+ .append("complete");
+
+ QFile file( fileName );
+ if ( file.open(QIODevice::ReadWrite) )
{
- quint64 address = regex.cap(2).toULongLong(0, 16);
- quint64 offset = regex.cap(3).toULongLong(0, 16);
- quint64 size = regex.cap(4).toULongLong(0, 16);
+ QDataStream stream( &file );
+ stream.writeRawData(buffer, size);
+ file.close();
+ }
+}
- QByteArray data;
- data.resize(size);
+quint64 PageVerifier::findMemAddressOfSegment(elfParseData context,
QString sectionName)
+{
+ //Find the address of the current section in the memory image
+ //Get Number of sections in kernel image
+ Instance attrs = context.currentModule.member("sect_attrs",
BaseType::trAny);
+ uint attr_cnt = attrs.member("nsections").toUInt32();
- // Seek
- if (!f.seek(offset))
+ //Now compare all section names until we find the correct section.
+ for (uint j = 0; j < attr_cnt; ++j) {
+ Instance attr = attrs.member("attrs").arrayElem(j);
+ if(attr.member("name").toString().remove(QChar('"'),
Qt::CaseInsensitive).
+ compare(sectionName) == 0)
{
- debugerr("Could not seek to position " << offset << "!");
- return;
+ return attr.member("address").toULong();
}
+ }
+ return 0;
+}
- // Read
- if ((quint64)f.read(data.data(), size) != size)
+PageVerifier::SegmentInfo PageVerifier::findElfSegmentWithName(char *
elfEhdr, QString sectionName)
+{
+ char * tempBuf = 0;
+
+ if(elfEhdr[4] == ELFCLASS32)
+ {
+ //TODO
+ }
+ else if(elfEhdr[4] == ELFCLASS64)
+ {
+ Elf64_Ehdr * elf64Ehdr = (Elf64_Ehdr *) elfEhdr;
+ Elf64_Shdr * elf64Shdr = (Elf64_Shdr *) (elfEhdr +
elf64Ehdr->e_shoff);
+ for(unsigned int i = 0; i < elf64Ehdr->e_shnum; i++)
{
- debugerr("An error occurred while reading " << size << " bytes
from pos " << offset << "!");
+ tempBuf = elfEhdr +
elf64Shdr[elf64Ehdr->e_shstrndx].sh_offset + elf64Shdr[i].sh_name;
+
+ if (sectionName.compare(tempBuf) == 0){
+ return SegmentInfo(elfEhdr + elf64Shdr[i].sh_offset,
elf64Shdr[i].sh_addr, elf64Shdr[i].sh_size);
+ //printf("Found Strtab in Section %i: %s\n", i, tempBuf);
+ }
+ }
+ }
+ return SegmentInfo();
+}
+
+quint64 PageVerifier::findElfAddressOfVariable(char * elfEhdr,
PageVerifier::elfParseData context, QString symbolName)
+{
+ if(elfEhdr[4] == ELFCLASS32)
+ {
+ //TODO
+ }
+ else if(elfEhdr[4] == ELFCLASS64)
+ {
+ Elf64_Ehdr * elf64Ehdr = (Elf64_Ehdr *) elfEhdr;
+ Elf64_Shdr * elf64Shdr = (Elf64_Shdr *) (elfEhdr +
elf64Ehdr->e_shoff);
+
+ quint32 symSize = elf64Shdr[context.symindex].sh_size;
+ Elf64_Sym *symBase = (Elf64_Sym *) (elfEhdr +
elf64Shdr[context.symindex].sh_offset);
+
+ for(Elf64_Sym * sym = symBase; sym < (Elf64_Sym *) (((char*)
symBase) + symSize) ; sym++)
+ {
+ QString currentSymbolName = QString(&((elfEhdr +
elf64Shdr[context.strindex].sh_offset)[sym->st_name]));
+ if(symbolName.compare(currentSymbolName) == 0)
+ {
+ return sym->st_value;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Undefined instruction for dealing with missing ops pointers. */
+static const char ud2a[] = { 0x0f, 0x0b };
+
+quint8 PageVerifier::paravirt_patch_nop(void) { return 0; }
+
+quint8 PageVerifier::paravirt_patch_ignore(unsigned len) { return len; }
+
+quint8 PageVerifier::paravirt_patch_insns(void *insnbuf, unsigned len,
+ const char *start, const char *end)
+{
+ quint8 insn_len = end - start;
+
+ if (insn_len > len || start == NULL)
+ insn_len = len;
+ else
+ memcpy(insnbuf, start, insn_len);
+
+ return insn_len;
+}
+
+quint8 PageVerifier::paravirt_patch_jmp(void *insnbuf, quint64 target,
quint64 addr, quint8 len)
+{
+ if (len < 5) return len;
+
+ quint32 delta = target - (addr + 5);
+
+ *((char*) insnbuf) = 0xe9;
+ *((quint32*) ((char*) insnbuf + 1)) = delta;
+
+ Console::out() << "Patching jump @ " << hex << addr << dec << endl;
+
+ return 5;
+}
+
+quint8 PageVerifier::paravirt_patch_call(void *insnbuf, quint64 target,
quint16 tgt_clobbers, quint64 addr, quint16 site_clobbers, quint8 len)
+{
+ if (tgt_clobbers & ~site_clobbers) return len;
+ if (len < 5) return len;
+
+ quint32 delta = target - (addr + 5);
+
+ *((char*) insnbuf) = 0xe8;
+ *((quint32*) ((char*) insnbuf + 1)) = delta;
+
+ return 5;
+}
+
+
+#define CLBR_ANY ((1 << 4) - 1)
+
+quint64 PageVerifier::get_call_destination(quint32 type)
+{
+ //These structs contain a function pointers.
+ //In memory they are directly after each other.
+ //Thus type is an index into the resulting array.
+
+ Instance pv_init_ops =
_sym.factory().findVarByName("pv_init_ops")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+ Instance pv_time_ops =
_sym.factory().findVarByName("pv_time_ops")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+ Instance pv_cpu_ops =
_sym.factory().findVarByName("pv_cpu_ops")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+ Instance pv_irq_ops =
_sym.factory().findVarByName("pv_irq_ops")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+ Instance pv_apic_ops =
_sym.factory().findVarByName("pv_apic_ops")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+ Instance pv_mmu_ops =
_sym.factory().findVarByName("pv_mmu_ops")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+ Instance pv_lock_ops =
_sym.factory().findVarByName("pv_lock_ops")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+
+ if(type < pv_init_ops.size()) return
pv_init_ops.memberByOffset(type).toUInt64();
+ type -= pv_init_ops.size();
+ if(type < pv_time_ops.size()) return
pv_time_ops.memberByOffset(type).toUInt64();
+ type -= pv_time_ops.size();
+ if(type < pv_cpu_ops.size()) return
pv_cpu_ops.memberByOffset(type).toUInt64();
+ type -= pv_cpu_ops.size();
+ if(type < pv_irq_ops.size()) return
pv_irq_ops.memberByOffset(type).toUInt64();
+ type -= pv_irq_ops.size();
+ if(type < pv_apic_ops.size()) return
pv_apic_ops.memberByOffset(type).toUInt64();
+ type -= pv_apic_ops.size();
+ if(type < pv_mmu_ops.size()) return
pv_mmu_ops.memberByOffset(type).toUInt64();
+ type -= pv_mmu_ops.size();
+ if(type < pv_lock_ops.size()) return
pv_lock_ops.memberByOffset(type).toUInt64();
+
+ return 0;
+}
+
+/* Simple instruction patching code. */
+#define DEF_NATIVE(ops, name, code) \
+ extern const char start_##ops##_##name[], end_##ops##_##name[]; \
+ asm("start_" #ops "_" #name ": " code "; end_" #ops "_" #name ":")
+
+#define str(x) #x
+
+DEF_NATIVE(pv_irq_ops, irq_disable, "cli");
+DEF_NATIVE(pv_irq_ops, irq_enable, "sti");
+DEF_NATIVE(pv_irq_ops, restore_fl, "pushq %rdi; popfq");
+DEF_NATIVE(pv_irq_ops, save_fl, "pushfq; popq %rax");
+DEF_NATIVE(pv_cpu_ops, iret, "iretq");
+DEF_NATIVE(pv_mmu_ops, read_cr2, "movq %cr2, %rax");
+DEF_NATIVE(pv_mmu_ops, read_cr3, "movq %cr3, %rax");
+DEF_NATIVE(pv_mmu_ops, write_cr3, "movq %rdi, %cr3");
+DEF_NATIVE(pv_mmu_ops, flush_tlb_single, "invlpg (%rdi)");
+DEF_NATIVE(pv_cpu_ops, clts, "clts");
+DEF_NATIVE(pv_cpu_ops, wbinvd, "wbinvd");
+
+DEF_NATIVE(pv_cpu_ops, irq_enable_sysexit, "swapgs; sti; sysexit");
+DEF_NATIVE(pv_cpu_ops, usergs_sysret64, "swapgs; sysretq");
+DEF_NATIVE(pv_cpu_ops, usergs_sysret32, "swapgs; sysretl");
+DEF_NATIVE(pv_cpu_ops, swapgs, "swapgs");
+
+DEF_NATIVE(, mov32, "mov %edi, %eax");
+DEF_NATIVE(, mov64, "mov %rdi, %rax");
+
+quint8 PageVerifier::paravirt_patch_default(quint32 type, quint16
clobbers, void *insnbuf,
+ quint64 addr, quint8 len)
+{
+ quint8 ret = 0;
+ //Get Memory of paravirt_patch_template + type
+ quint64 opfunc = get_call_destination(type);
+
+// Console::out() << "Call address is: " << hex
+// << opfunc << " "
+// << dec << endl;
+
+ quint64 nopFuncAddress = 0;
+ quint64 ident32NopFuncAddress = 0;
+ quint64 ident64NopFuncAddress = 0;
+
+ BaseType* btFunc = 0;
+ const Function* func = 0;
+ btFunc = _sym.factory().typesByName().value("_paravirt_nop");
+ if( btFunc && btFunc->type() == rtFunction && btFunc->size() > 0)
+ {
+ func = dynamic_cast<const Function*>(btFunc);
+ nopFuncAddress = func->pcLow();
+ }
+ btFunc = _sym.factory().typesByName().value("_paravirt_ident_32");
+ if( btFunc && btFunc->type() == rtFunction && btFunc->size() > 0)
+ {
+ func = dynamic_cast<const Function*>(btFunc);
+ ident32NopFuncAddress = func->pcLow();
+ }
+ btFunc = _sym.factory().typesByName().value("_paravirt_ident_64");
+ if( btFunc && btFunc->type() == rtFunction && btFunc->size() > 0)
+ {
+ func = dynamic_cast<const Function*>(btFunc);
+ ident64NopFuncAddress = func->pcLow();
+ }
+
+
+ //Get pv_cpu_ops to check offsets in else clause
+ const Structured * pptS = dynamic_cast<const
Structured*>(_sym.factory().findBaseTypeByName("paravirt_patch_template"));
+ qint64 pv_cpu_opsOffset = pptS->memberOffset("pv_cpu_ops");
+ Instance pv_cpu_ops =
_sym.factory().findVarByName("pv_cpu_ops")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+
+ if (!opfunc)
+ {
+ // opfunc == NULL
+ /* If there's no function, patch it with a ud2a (BUG) */
+ //If this is a module this is a bug anyway so this should not
happen.
+ //ret = paravirt_patch_insns(insnbuf, len, ud2a,
ud2a+sizeof(ud2a));
+ //If this the kernel this can happen and is only filled with nops
+ ret = paravirt_patch_nop();
+ }
+ //TODO get address of Function Paravirt nop
+ else if (opfunc == nopFuncAddress)
+ /* If the operation is a nop, then nop the callsite */
+ ret = paravirt_patch_nop();
+
+ /* identity functions just return their single argument */
+ else if (opfunc == ident32NopFuncAddress)
+ ret = paravirt_patch_insns(insnbuf, len, start__mov32, end__mov32);
+ else if (opfunc == ident64NopFuncAddress)
+ ret = paravirt_patch_insns(insnbuf, len, start__mov64, end__mov64);
+
+ else if (type == pv_cpu_opsOffset + pv_cpu_ops.memberOffset("iret") ||
+ type == pv_cpu_opsOffset +
pv_cpu_ops.memberOffset("irq_enable_sysexit") ||
+ type == pv_cpu_opsOffset +
pv_cpu_ops.memberOffset("usergs_sysret32") ||
+ type == pv_cpu_opsOffset +
pv_cpu_ops.memberOffset("usergs_sysret64"))
+ /* If operation requires a jmp, then jmp */
+ ret = paravirt_patch_jmp(insnbuf, opfunc, addr, len);
+ else
+ {
+ /* Otherwise call the function; assume target could
+ clobber any caller-save reg */
+ ret = paravirt_patch_call(insnbuf, opfunc, CLBR_ANY,
+ addr, clobbers, len);
+ }
+ return ret;
+}
+
+quint32 PageVerifier::paravirtNativePatch(quint32 type, quint16 clobbers,
void *ibuf,
+ unsigned long addr, unsigned len)
+{
+ quint32 ret = 0;
+
+ const Structured * pptS = dynamic_cast<const
Structured*>(_sym.factory().findBaseTypeByName("paravirt_patch_template"));
+
+ qint64 pv_irq_opsOffset = pptS->memberOffset("pv_irq_ops");
+ Instance pv_irq_ops =
_sym.factory().findVarByName("pv_irq_ops")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+ qint64 pv_cpu_opsOffset = pptS->memberOffset("pv_cpu_ops");
+ Instance pv_cpu_ops =
_sym.factory().findVarByName("pv_cpu_ops")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+ qint64 pv_mmu_opsOffset = pptS->memberOffset("pv_mmu_ops");
+ Instance pv_mmu_ops =
_sym.factory().findVarByName("pv_mmu_ops")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+
+
+#define PATCH_SITE(ops, x) \
+ else if(type == ops##Offset + ops.memberOffset("" #x )) \
+ { \
+ ret = paravirt_patch_insns(ibuf, len, start_##ops##_##x,
end_##ops##_##x); \
+ }
+
+ if(false){}
+ PATCH_SITE(pv_irq_ops, restore_fl)
+ PATCH_SITE(pv_irq_ops, save_fl)
+ PATCH_SITE(pv_irq_ops, irq_enable)
+ PATCH_SITE(pv_irq_ops, irq_disable)
+ PATCH_SITE(pv_cpu_ops, iret)
+ PATCH_SITE(pv_cpu_ops, irq_enable_sysexit)
+ PATCH_SITE(pv_cpu_ops, usergs_sysret32)
+ PATCH_SITE(pv_cpu_ops, usergs_sysret64)
+ PATCH_SITE(pv_cpu_ops, swapgs)
+ PATCH_SITE(pv_mmu_ops, read_cr2)
+ PATCH_SITE(pv_mmu_ops, read_cr3)
+ PATCH_SITE(pv_mmu_ops, write_cr3)
+ PATCH_SITE(pv_cpu_ops, clts)
+ PATCH_SITE(pv_mmu_ops, flush_tlb_single)
+ PATCH_SITE(pv_cpu_ops, wbinvd)
+
+ else
+ {
+ ret = paravirt_patch_default(type, clobbers, ibuf, addr, len);
+ }
+#undef PATCH_SITE
+ return ret;
+}
+
+
+void PageVerifier::add_nops(void *insns, quint8 len)
+{
+ while (len > 0) {
+ unsigned int noplen = len;
+ if (noplen > ASM_NOP_MAX)
+ noplen = ASM_NOP_MAX;
+ memcpy(insns, ideal_nops[noplen], noplen);
+ insns = (void *) ((char*) insns + noplen);
+ len -= noplen;
+ }
+}
+
+int PageVerifier::apply_relocate(char * fileContent, Elf32_Shdr *sechdrs,
elfParseData context)
+{
+ Q_UNUSED(fileContent);
+ Q_UNUSED(sechdrs);
+ Q_UNUSED(context);
+ debugerr("Function apply_relocate currently not implemented");
+ //TODO i386 code
+ return 0;
+}
+
+/**
+ * Apply Relocations for kernel module based on elf headers.
+ * Taken directly out of module.c from linux kernel
+ * This function handles the x86_64 relocations.
+ */
+int PageVerifier::apply_relocate_add(char * fileContent, Elf64_Shdr
*sechdrs, elfParseData context)
+{
+ Elf64_Rela *rel = (Elf64_Rela *) (fileContent +
sechdrs[context.relsec].sh_offset);
+ Elf32_Word sectionId = sechdrs[context.relsec].sh_info;
+ QString sectionName = QString(fileContent +
sechdrs[context.shstrindex].sh_offset + sechdrs[sectionId].sh_name);
+
+ //Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+
+ Elf64_Sym *symBase = (Elf64_Sym *) (fileContent +
sechdrs[context.symindex].sh_offset);
+ Elf64_Sym *sym;
+
+ void *locInElf = 0;
+ void *locInMem = 0;
+ void *locOfRelSectionInMem = 0;
+ void *locOfRelSectionInElf = 0;
+ quint64 val;
+ quint64 i;
+
+ void *sectionBaseElf = (void *) (fileContent +
sechdrs[sectionId].sh_offset);
+ void *sectionBaseMem = 0;
+
+ sectionBaseMem = (void *) findMemAddressOfSegment(context,
sectionName);
+
+ bool doPrint = false;
+
+ //if(sectionName.compare(".text") == 0) doPrint = true;
+
+ if(doPrint) Console::out() << "Section to Relocate: " << sectionName
<< dec << endl;
+
+ for (i = 0; i < sechdrs[context.relsec].sh_size / sizeof(*rel); i++) {
+ /* This is where to make the change */
+ //loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ // + rel[i].r_offset;
+ locInElf = (void *) ((char*)sectionBaseElf + rel[i].r_offset);
+ locInMem = (void *) ((char*)sectionBaseMem + rel[i].r_offset);
+
+ /* This is the symbol it is referring to. Note that all
+ undefined symbols have been resolved. */
+ //sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
+ // + ELF64_R_SYM(rel[i].r_info);
+ //sym = (Elf64_Sym *) (fileContent +
sechdrs[context.symindex].sh_offset)
+ // + ELF64_R_SYM(rel[i].r_info);
+ sym = symBase + ELF64_R_SYM(rel[i].r_info);
+
+ Variable* v = NULL;
+ Instance symbol;
+
+ QString symbolName = QString(&((fileContent +
sechdrs[context.strindex].sh_offset)[sym->st_name]));
+
+
/////////////////////////////////////////////////////////////////////
+ //if ((unsigned long) locInMem == 0xffffffffa0000006) doPrint =
true;
+ //if (rel[i].r_offset == 0xf1f) doPrint = true;
+ //if (symbolName.compare("copy_user_generic_unrolled") == 0)
doPrint = true;
+
//if(context.currentModule.member("name").toString().compare("\"drm\"") ==
0 &&
+ // sectionName.compare(".altinstructions") == 0 && i <= 1)
doPrint = true;
+
/////////////////////////////////////////////////////////////////////
+
+ if(doPrint) Console::out() << endl;
+ if(doPrint) Console::out() << "Loc in Elf: " << hex << locInElf <<
dec << endl;
+ if(doPrint) Console::out() << "Loc in Mem: " << hex << locInMem <<
dec << endl;
+ if(doPrint) Console::out() << "Sym: " << hex << sym << " (Offset:
0x" << ELF64_R_SYM(rel[i].r_info) << " , Info: 0x" << sym->st_info << " )"
<< " Bind type: " << ELF64_ST_BIND(sym->st_info) << dec << endl;
+
+ if(doPrint) Console::out() << "Name of current Section: " <<
QString(fileContent + sechdrs[context.shstrindex].sh_offset +
sechdrs[sectionId].sh_name) << endl;
+ // Console::out() << "type " << (int)ELF64_R_TYPE(rel[i].r_info)
<< " st_value " << sym->st_value << " r_addend " << rel[i].r_addend << "
loc " << hex << (u64)loc << dec << endl;
+
+ switch(sym->st_shndx){
+ case SHN_COMMON:
+ //printf("Sym Type: SHN_COMMON\n");
+ debugerr("This should not happen!");
+ continue; //TODO REMOVE
+ break;
+ case SHN_ABS:
+ //printf("Sym Type: SHN_ABS\n");
+ //printf("Nothing to do!\n");
+ continue; // TODO REMOVE
+ break;
+ case SHN_UNDEF:
+ //debugerr("Sym Type: SHN_UNDEF");
+
+ //Resolve Symbol and write to st_value
+ if(doPrint) Console::out() << "SHN_UNDEF: Trying to find
symbol " << symbolName << endl;
+ if(doPrint) Console::out() << "System Map contains " <<
_sym.memSpecs().systemMap.count(symbolName) << " Versions of that symbol."
<< endl;
+
+
+ if(_symTable.contains(symbolName))
+ {
+ sym->st_value = _symTable.value(symbolName);
+ if(doPrint) Console::out() << "Found symbol @" << hex <<
sym->st_value << dec << endl;
+ }
+ //Try to find variable in system map
+ else if (_sym.memSpecs().systemMap.count(symbolName) > 0)
+ {
+ //Console::out() << "Found Variable in system.map: " <<
&((fileContent + sechdrs[strindex].sh_offset)[sym->st_name]) << endl;
+ //sym->st_value =
_sym.memSpecs().systemMap.value(symbolName).address;
+ QList<SystemMapEntry> symbols =
_sym.memSpecs().systemMap.values(symbolName);
+ for (QList<SystemMapEntry>::iterator i = symbols.begin();
i != symbols.end(); ++i)
+ {
+ SystemMapEntry currentEntry = (*i);
+
+ //ELF64_ST_BIND(sym->st_info) => 0: Local, 1: Global,
2: Weak
+ //currentEntry.type => 'ascii' lowercase: local,
uppercase: global
+ if (ELF64_ST_BIND(sym->st_info) == 1 &&
currentEntry.type >= 0x41 && currentEntry.type <= 0x5a)
+ {
+ if(doPrint) Console::out() << "Symbol found in
System Map: " << hex << currentEntry.address << " With type: Global" << dec
<< endl;
+ sym->st_value = currentEntry.address;
+ }
+ else if (ELF64_ST_BIND(sym->st_info) == 0 &&
currentEntry.type >= 0x61 && currentEntry.type <= 0x7a)
+ {
+ if(doPrint) Console::out() << "Symbol found in
System Map: " << hex << currentEntry.address << " With type: Local" << dec
<< endl;
+ sym->st_value = currentEntry.address;
+ }
+ }
+ }
+ else
+ {
+ //Console::out() << "Variable not found in system.map: "
<< &((fileContent + sechdrs[strindex].sh_offset)[sym->st_name]) << endl;
+ //Try to find the variable by name in insight.
+ v = _sym.factory().findVarByName(symbolName);
+ if (!v)
+ {
+ //debugerr("Variable " << &((fileContent +
sechdrs[strindex].sh_offset)[sym->st_name]) << " not found! ERROR!");
+ QList<BaseType*> types =
_sym.factory().typesByName().values(symbolName);
+
+ if(types.size() > 0)
+ {
+ BaseType* bt;
+ //Console::out() << "Type found in insight: " <<
&((fileContent + sechdrs[strindex].sh_offset)[sym->st_name]) << endl;
+ for(int k = 0 ; k < types.size() ; k++)
+ {
+ bt =
types.at(k);
+ //Console::out() << k << ": " << (bt &&
(bt->type() == rtFunction) ? "function" : "type") << " with size " <<
bt->size() << endl;
+ // Only use the type if it is a function and
got a defined size
+ if( bt->type() == rtFunction && bt->size() >
0) { break; }
+
+ if(k == types.size() - 1)
+ {
+ //Console::out() << "Function not found in
insight: " << symbolName << endl;
+ //TODO handle this case does this happen??
+ }
+ }
+ const Function* func = dynamic_cast<const
Function*>(bt);
+
+ if (func) {
+ sym->st_value = func->pcLow();
+ if(doPrint) Console::out() << "Function found
in: " << hex << sym->st_value << dec << endl;
+ //TODO check if somewhere the startaddress is
zero! bug!
+// Console::out() << Console::color(ctColHead)
<< " Start Address: "
+// << Console::color(ctAddress) <<
QString("0x%1").arg(
+//
func->pcLow(),
+//
_sym.memSpecs().sizeofPointer << 1,
+// 16,
+// QChar('0'))
+// << Console::color(ctReset)
+// << endl;
+ }
+
+ } //Else no type with with the given name found.
+ continue;
+ }
+ //Console::out() << "Variable found in insight: " <<
&((fileContent + sechdrs[strindex].sh_offset)[sym->st_name]) << endl;
+ symbol = v->toInstance(_vmem, BaseType::trLexical, ksAll);
+ if(!symbol.isValid())
+ {
+ debugerr("Symbol " << symbolName << " not found!
ERROR!");
+ continue;
+ }
+ //Console::out() << "Symbol found with address : 0x" <<
hex << symbol.address() << dec << endl;
+ sym->st_value = symbol.address();
+
+ if(doPrint) Console::out() << "Instance found: " << hex <<
sym->st_value << dec << endl;
+
+ }
+
+ break;
+ default:
+ if(doPrint) Console::out() << "default: " << endl;
+ //debugerr("Sym Type: default: " << sym->st_shndx);
+
+ //TODO this is not right yet.
+ /* Divert to percpu allocation if a percpu var. */
+ if (sym->st_shndx == context.percpuDataSegment)
+ {
+ locOfRelSectionInMem =
context.currentModule.member("percpu").toPointer();
+ //sym->st_value += (unsigned long)mod_percpu(mod);
+ if(doPrint) Console::out() << "Per CPU variable" << endl;
+ }
+ else
+ {
+ QString relocSection = QString(&((fileContent +
sechdrs[context.shstrindex].sh_offset)[sechdrs[sym->st_shndx].sh_name]));
+ locOfRelSectionInElf = (void *)
findElfSegmentWithName(fileContent, relocSection).index;
+ locOfRelSectionInMem = (void *)
findMemAddressOfSegment(context, relocSection);
+ if(doPrint) Console::out() << "SectionName: " << hex <<
relocSection << dec << endl;
+ }
+
+ //Only add the location of the section if it was not already
added
+ if(doPrint) Console::out() << "old st_value: " << hex <<
sym->st_value << dec;
+ if(doPrint) Console::out() << " locOfRelSectionInMem: " << hex
<< locOfRelSectionInMem << dec;
+ if(doPrint) Console::out() << " locOfRelSectionInElf: " << hex
<< locOfRelSectionInElf << dec << endl;
+
+ if(sym->st_value < (long unsigned int) locOfRelSectionInMem)
+ {
+ sym->st_value += (long unsigned int) locOfRelSectionInMem;
+ }
+
+ break;
+ }
+
+ val = sym->st_value + rel[i].r_addend;
+
+ if(doPrint) Console::out() << "raddend: " << hex <<
rel[i].r_addend << dec << endl;
+ if(doPrint) Console::out() << "sym->value: " << hex <<
sym->st_value << dec << endl;
+ if(doPrint) Console::out() << "val: " << hex << val << dec << endl;
+
+ switch (ELF64_R_TYPE(rel[i].r_info)) {
+ case R_X86_64_NONE:
+ break;
+ case R_X86_64_64:
+ *(quint64 *)locInElf = val;
+ break;
+ case R_X86_64_32:
+ *(quint32 *)locInElf = val;
+ if (val != *(quint32 *)locInElf)
+ goto overflow;
+ break;
+ case R_X86_64_32S:
+ *(qint32 *)locInElf = val;
+ if(doPrint) Console::out() << " 32S final value: " << hex <<
(qint32) val << dec << endl;
+ if ((qint64)val != *(qint32 *)locInElf)
+ goto overflow;
+ break;
+ case R_X86_64_PC32:
+
+ //This line is from the original source the loc here is the
location within the loaded module.
+ //val -= (u64)loc;
+ if(sectionName.compare(".altinstructions") == 0)
+ {
+ //This is later used to copy some memory
+ val = val - (quint64)locOfRelSectionInMem +
(quint64)locOfRelSectionInElf - (quint64)locInElf;
+ }
+ else
+ {
+ //This is used as relocation in memory
+ val -= (quint64)locInMem;
+ }
+ if(doPrint) Console::out() << "PC32 final value: " << hex <<
(quint32) val << dec << endl;
+ *(quint32 *)locInElf = val;
+#if 0
+ if ((qint64)val != *(qint32 *)loc)
+ goto overflow;
+#endif
+ break;
+ default:
+ debugerr("Unknown rela relocation: " <<
ELF64_R_TYPE(rel[i].r_info));
+ return -ENOEXEC;
+ }
+ doPrint = false;
+ }
+ return 0;
+
+overflow:
+ Console::err() << "overflow in relocation type " <<
(int)ELF64_R_TYPE(rel[i].r_info) << " val " << hex << val << endl;
+ Console::err() << "likely not compiled with -mcmodel=kernel" << endl;
+ return -ENOEXEC;
+}
+
+void PageVerifier::applyAltinstr(char * fileContent, SegmentInfo info,
elfParseData context)
+{
+ bool doPrint = false;
+ //if(context.type == Detect::KERNEL_CODE) doPrint = true;
+
+ struct alt_instr *start = (struct alt_instr*) info.index;
+ struct alt_instr *end = (struct alt_instr*) (info.index + info.size);
+
+
//if(context.currentModule.member("name").toString().compare("\"drm\"") ==
0) doPrint = true;
+
+ quint8 * instr;
+ quint8 * replacement;
+ char insnbuf[255-1];
+
+ for(struct alt_instr * a = start ; a < end ; a++)
+ {
+ //if (!boot_cpu_has(a->cpuid)) continue;
+
+ Instance boot_cpu_data =
_sym.factory().findVarByName("boot_cpu_data")->toInstance(_vmem,
BaseType::trLexical, ksAll);
+ Instance x86_capability = boot_cpu_data.member("x86_capability");
+
+ if (!((x86_capability.arrayElem(a->cpuid / 32).toUInt32() >>
(a->cpuid % 32)) & 0x1))
+ {
+ continue;
+ }
+
+ //doPrint = false;
+
//if(context.currentModule.member("name").toString().compare("\"drm\"") ==
0) doPrint = true;
+ //if(context.type == Detect::KERNEL_CODE) doPrint = true;
+
+ instr = ((quint8 *)&a->instr_offset) + a->instr_offset;
+ replacement = ((quint8 *)&a->repl_offset) + a->repl_offset;
+
+ if(context.type == Detect::KERNEL_CODE)
+ {
+ instr -= (quint64)(context.textSegment.index - (quint64)
fileContent);
+ }
+
+ if(doPrint) Console::out() << "Applying alternative at offset: "
<< hex << (void*) (instr - (quint8*) context.textSegment.index) << dec <<
endl;
+
+ if(doPrint) Console::out() << hex << "instr: @" << (void*) instr
<< " len: " << a->instrlen << " offset: " << (void*) (instr - (quint64)
context.textSegment.index) <<
+ " replacement: @" << (void*)
replacement << " len: " << a->replacementlen << " offset: " << (void*)
(replacement - (quint64)
findElfSegmentWithName(fileContent, ".altinstr_replacement").index) << dec
<< endl;
+
+ if(doPrint) Console::out() << "CPU ID is: " << hex << a->cpuid <<
dec << endl;
+
+ //TODO REMOVE
+ //#define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit)
+ //test_cpu_cap(c, bit))
+ //test_bit(bit, (unsigned long *)((c)->x86_capability))
+
+ //#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+ //static inline int test_bit(int nr, const volatile unsigned long
*addr)
+ //{
+ // return 1UL & (addr[BIT_WORD(nr)] >> (nr &
(BITS_PER_LONG-1)));
+ //}
+
+
+ memcpy(insnbuf, replacement, a->replacementlen);
+
+ // 0xe8 is a relative jump; fix the offset.
+ if (insnbuf[0] == (char) 0xe8 && a->replacementlen == 5)
+ {
+ SegmentInfo altinstr =
findElfSegmentWithName(fileContent, ".altinstr_replacement");
+
+ //If replacement is in the altinstr_replace section fix the
offset.
+ if(replacement >= (quint8 *)altinstr.index && replacement <
(quint8 *)altinstr.index + altinstr.size)
+ {
+ quint64 altinstrSegmentInMem = 0;
+ quint64 textSegmentInMem = 0;
+
+ if(context.type == Detect::KERNEL_CODE)
+ {
+ altinstrSegmentInMem =
findElfSegmentWithName(fileContent, ".altinstr_replacement").address;
+ textSegmentInMem =
findElfSegmentWithName(fileContent, ".text").address;
+ }
+ else if(context.type == Detect::MODULE)
+ {
+ altinstrSegmentInMem =
findMemAddressOfSegment(context, ".altinstr_replacement");
+ textSegmentInMem =
findMemAddressOfSegment(context, ".text");
+ }
+
+ if(doPrint) Console::out() << hex << "Altinstr in Mem: "
<< altinstrSegmentInMem << " Text in Mem: " << textSegmentInMem << dec <<
endl;
+
+ //Adapt offset in ELF
+ *(qint32 *)(insnbuf + 1) -= (altinstr.index -
context.textSegment.index) - (altinstrSegmentInMem - textSegmentInMem);
+
+ if(doPrint) Console::out() << "Offset: " << hex <<
altinstr.index - context.textSegment.index - (altinstrSegmentInMem -
textSegmentInMem) << dec << endl;
+ }
+ *(qint32 *)(insnbuf + 1) += replacement - instr;
+ }
+
+ //add_nops
+ add_nops(insnbuf + a->replacementlen, a->instrlen -
a->replacementlen); //add_nops
+
+ memcpy(instr, insnbuf, a->instrlen);
+ }
+}
+
+void PageVerifier::applyParainstr(SegmentInfo info, elfParseData context)
+{
+ struct paravirt_patch_site *start = (struct paravirt_patch_site *)
info.index;
+ struct paravirt_patch_site *end = (struct paravirt_patch_site *)
(info.index + info.size);
+
+ char insnbuf[254];
+
+ //noreplace_paravirt is 0 in the kernel
+
//
http://lxr.free-electrons.com/source/arch/x86/kernel/alternative.c#L45
+ //if (noreplace_paravirt) return;
+
+ quint64 textInMem = 0;
+ if(context.type == Detect::MODULE)
+ {
+ textInMem = findMemAddressOfSegment(context, ".text");
+ }
+ else
+ {
+ //This is the case, when we parse the kernel
+ textInMem = _sym.memSpecs().systemMap.value("_text").address;
+ }
+
+ for (struct paravirt_patch_site *p = start; p < end; p++) {
+ unsigned int used;
+
+ //BUG_ON(p->len > MAX_PATCH_LEN);
+ if(p->len > 254) debugerr("parainstructions: impossible length");
+
+ //p->instr points to text segment in memory
+ //let it point to the address in the elf binary
+
+ quint8 * instrInElf = p->instr;
+ instrInElf -= textInMem;
+ instrInElf += (quint64) context.textSegment.index;
+
+ /* prep the buffer with the original instructions */
+ memcpy(insnbuf, instrInElf, p->len);
+
+ //p->instrtype is use as an offset to an array of pointers. With
insight we only use ist as Offset.
+ used = paravirtNativePatch(p->instrtype * 8, p->clobbers, insnbuf,
+ (unsigned long)p->instr, p->len);
+
+ if(p->len > 254) debugerr("parainstructions: impossible length");
***The diff for this file has been truncated for email.***
=======================================
--- /trunk/libinsight/include/insight/detect.h Fri Jul 12 12:57:46 2013 UTC
+++ /trunk/libinsight/include/insight/detect.h Wed Sep 11 14:27:18 2013 UTC
@@ -4,6 +4,8 @@
#include "kernelsymbols.h"
#include "function.h"
+#include <elf.h>
+
class Detect : public LongOperation
{
public:
@@ -41,18 +43,6 @@
QByteArray data;
};
- struct ExecutableSection
- {
- ExecutableSection() : name(""), address(0), offset(0), data() {}
- ExecutableSection(QString name, quint64 address, quint64 offset,
QByteArray data) :
- name(name), address(address), offset(offset),
data(data) {}
-
- QString name;
- quint64 address;
- quint64 offset;
- QByteArray data;
- };
-
struct FunctionPointerStats
{
FunctionPointerStats() : total(0), userlandPointer(0),
defaultValue(0),
@@ -111,17 +101,15 @@
quint64 _final_page;
QString _current_file;
- QMultiHash<QString, ExecutableSection> *ExecutableSections;
QMultiHash<quint64, FunctionInfo> *Functions;
+
const KernelSymbols &_sym;
quint64 _current_index;
static QMultiHash<quint64, ExecutablePage> *ExecutablePages;
- void getExecutableSections(QString file);
quint64 inVmap(quint64 address, VirtualMemory *vmem);
- void verifyHashes(QMultiHash<quint64, ExecutablePage> *current);
void buildFunctionList(MemoryMap *map);
bool pointsToKernelFunction(MemoryMap *map, Instance &funcPointer);
bool pointsToModuleCode(Instance &functionPointer);
@@ -130,4 +118,125 @@
void verifyFunctionPointers(MemoryMap *map);
};
+class PageVerifier : public LongOperation
+{
+public:
+
+ struct PageData{
+ QByteArray hash;
+ QByteArray content;
+ };
+
+ struct SegmentInfo{
+ SegmentInfo(): index(0), address(0), size(0) {}
+ SegmentInfo(char * i, unsigned int s): index(i), address(0),
size(s) {}
+ SegmentInfo(char * i, quint64 a, unsigned int s): index(i),
address(a), size(s) {}
+
+ char * index;
+ quint64 address;
+ unsigned int size;
+ };
+
+ struct elfParseData{
+ elfParseData() :
+ type(Detect::UNDEFINED),
+ symindex(0), strindex(0),
+ textSegment(), dataSegment(), vvarSegment(),
dataNosaveSegment(), bssSegment(),
+ fentryAddress(0), genericUnrolledAddress(0),
+ percpuDataSegment(0), textSegmentData(), vvarSegmentData(),
dataNosaveSegmentData(),
+ jumpTable(), currentModule()
+ {}
+ elfParseData(Instance curMod) :
+ type(Detect::UNDEFINED),
+ symindex(0), strindex(0),
+ textSegment(), dataSegment(), vvarSegment(),
dataNosaveSegment(), bssSegment(),
+ fentryAddress(0), genericUnrolledAddress(0),
+ percpuDataSegment(0), textSegmentData(), vvarSegmentData(),
dataNosaveSegmentData(),
+ jumpTable(), currentModule(curMod)
+ {}
+
+ Detect::PageType type;
+ unsigned int symindex;
+ unsigned int strindex;
+ unsigned int shstrindex;
+ SegmentInfo textSegment;
+ SegmentInfo dataSegment;
+ SegmentInfo vvarSegment;
+ SegmentInfo dataNosaveSegment;
+ SegmentInfo bssSegment;
+ unsigned int relsec;
+ quint64 fentryAddress;
+ quint64 genericUnrolledAddress;
+ unsigned int percpuDataSegment;
+ QList<PageData> textSegmentData;
+ QList<PageData> vvarSegmentData;
+ QList<PageData> dataNosaveSegmentData;
+ QByteArray jumpTable;
+ Instance currentModule;
+ };
+
+ PageVerifier(const KernelSymbols &sym);
+
+ void verifyHashes(QMultiHash<quint64, Detect::ExecutablePage>
*current);
+ void operationProgress();
+
+private:
+ const KernelSymbols &_sym;
+ VirtualMemory *_vmem;
+
+ const unsigned char * const * ideal_nops;
+
+ quint64 _current_index;
+
+ QMultiHash<QString, elfParseData> * ParsedExecutables;
+ QHash<QString, quint64> _symTable;
+
+ QHash<quint64, qint32> _jumpEntries;
+
+ QString findModuleFile(QString moduleName);
+ char* readFile(QString fileName);
+ void writeSectionToFile(QString moduleName, quint32 sectionNumber,
QByteArray data);
+ void writeModuleToFile(QString origFileName, Instance currentModule,
char * buffer );
+ quint64 findMemAddressOfSegment(elfParseData context, QString
sectionName);
+
+ int apply_relocate(char * fileContent, Elf32_Shdr *sechdrs,
elfParseData context);
+ int apply_relocate_add(char * fileContent, Elf64_Shdr *sechdrs,
elfParseData context);
+
+
+ void add_nops(void *insns, quint8 len);
+
+ quint8 paravirt_patch_nop(void);
+ quint8 paravirt_patch_ignore(unsigned len);
+ quint8 paravirt_patch_insns(void *insnbuf, unsigned len,
+ const char *start, const char *end);
+ quint8 paravirt_patch_jmp(void *insnbuf, quint64 target, quint64 addr,
quint8 len);
+ quint8 paravirt_patch_call(void *insnbuf, quint64 target, quint16
tgt_clobbers,
+ quint64 addr, quint16 site_clobbers, quint8
len);
+ quint8 paravirt_patch_default(quint32 type, quint16 clobbers, void
*insnbuf,
+ quint64 addr, quint8 len);
+ quint32 paravirtNativePatch(quint32 type, quint16 clobbers, void *ibuf,
+ unsigned long addr, unsigned len);
+
+ quint64 get_call_destination(quint32 type);
+
+ void applyAltinstr(char * fileContent, SegmentInfo info, elfParseData
context);
+ void applyParainstr(SegmentInfo info, elfParseData context);
+ void applyMcount(SegmentInfo info, elfParseData context, QByteArray
&segmentData);
+ void applyTracepoints(SegmentInfo tracePoint, SegmentInfo rodata,
elfParseData context, QByteArray &segmentData);
+ void applyJumpEntries(QByteArray &textSegmentContent,
PageVerifier::elfParseData context, quint64 jumpStart = 0, quint64 jumpStop
= 0);
+
+ SegmentInfo findElfSegmentWithName(char * elfEhdr, QString
sectionName);
+ Instance findModuleByName(QString moduleName);
+ quint64 findElfAddressOfVariable(char * elfEhdr, elfParseData context,
QString symbolName);
+
+ elfParseData parseKernelModule(QString fileName, Instance
currentModule);
+ void loadElfModule(QString moduleName, Instance currentModule);
+
+ elfParseData parseKernel(QString fileName);
+ void loadElfKernel();
+
+ quint64 checkCodePage(QString moduleName, quint32 sectionNumber,
Detect::ExecutablePage currentPage);
+
+};
+
#endif // DETECT_H