4
1
mirror of https://github.com/QuasarApp/CQtDeployer.git synced 2025-05-10 08:29:35 +00:00

added support for read pe Libs

This commit is contained in:
Andrei Yankovich 2019-03-23 20:40:33 +03:00
parent c09c584b66
commit 9976120671
11 changed files with 69 additions and 409 deletions

1
.gitignore vendored

@ -58,3 +58,4 @@ distro/
staticQt/
staticQtWin64/
build

3
.gitmodules vendored

@ -10,3 +10,6 @@
[submodule "CQtDeployerBinaries"]
path = CQtDeployerBinaries
url = https://github.com/QuasarApp/CQtDeployerBinaries.git
[submodule "pe"]
path = pe
url = https://github.com/QuasarApp/pe-parse.git

@ -9,6 +9,7 @@ TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += QuasarAppLib \
Pe \
Deploy \
CQtDeployer \
UnitTests
@ -28,6 +29,7 @@ CQtDeployer.depends=QuasarAppLib
CQtDeployer.depends=Deploy
QuasarAppLib.file = $$PWD/QuasarAppLib/QuasarApp.pro
Pe.file = $$PWD/pe/pe-parser-library/pe-parser.pro
win32:include('$$PWD/CQtDeployerWinBuild.pri')

@ -29,6 +29,8 @@ CONFIG(release, debug|release): {
include('$$PWD/../QuasarAppLib/QuasarLib.pri')
include('$$PWD/../Deploy/Deploy.pri')
include('$$PWD/../pe/pe-parser-library/pe-parser.pri')
TARGET = cqtdeployer

@ -37,6 +37,7 @@ CONFIG(release, debug|release): {
}
include('$$PWD/../QuasarAppLib/QuasarLib.pri')
include('$$PWD/../pe/pe-parser-library/pe-parser.pri')
SOURCES += \

@ -2,211 +2,50 @@
#include <QFile>
#include <QFileInfo>
#include <QSet>
#include <QVector>
#include <parse.h>
bool PE::readSectionsHeaders(const LIB_META_INFO & info,
QVector<IMAGE_SECTION_HEADER> &sections,
QFile& file) {
#include <bits/stl_set.h>
if (!file.isOpen()) {
return false;
}
namespace peparse {
sections.clear();
class section;
if (static_cast<RunType>(info.type) == RunType::_32bit) {
if (!file.seek(info.PEIndex + SECTION_HEADER_32)) {
return false;
}
struct importent {
VA addr;
std::string symbolName;
std::string moduleName;
};
sections.resize(info.rawSectionCount);
file.read(reinterpret_cast<char*>(sections.data()),
sizeof (IMAGE_SECTION_HEADER) * info.rawSectionCount);
class reloc;
class exportent;
class symbol;
return true;
}
else if (static_cast<RunType>(info.type) == RunType::_64bit) {
struct parsed_pe_internal {
std::vector<section> secs;
std::vector<resource> rsrcs;
std::vector<importent> imports;
std::vector<reloc> relocs;
std::vector<exportent> exports;
std::vector<symbol> symbols;
};
if (!file.seek(info.PEIndex + SECTION_HEADER_64)) {
return false;
}
sections.resize(info.rawSectionCount);
file.read(reinterpret_cast<char*>(sections.data()),
sizeof (IMAGE_SECTION_HEADER) * info.rawSectionCount);
return true;
}
return false;
}
DWORD PE::readSectionAligment(const LIB_META_INFO &info, QFile& file) {
bool PE::getDep(peparse::parsed_pe_internal * internal, QStringList &res) {
auto imports = internal->imports;
if (!file.isOpen()) {
return false;
}
std::set<std::string> filter;
if (!file.seek(info.PEIndex + SECTION_ALIGMENT_INDEX_32_64)) {
return false;
}
DWORD sectionAlign;
file.read(reinterpret_cast<char*>(&sectionAlign), sizeof (sectionAlign));
return sectionAlign;
}
unsigned short PE::findIndexPE(QFile &file) {
if (!file.isOpen()) {
return 0;
}
unsigned short limit = 0x400;
unsigned short currentSeeck = INDEX_PE_MAGIC;
unsigned short PE = 0x0;
while (currentSeeck <= limit) {
if (!file.seek(currentSeeck)) {
return 0;
}
file.read(reinterpret_cast<char*>(&PE), sizeof (PE));
if (PE == PE_MAGIC) {
return currentSeeck;
}
currentSeeck++;
}
return 0;
}
bool PE::fillMetaInfo(LIB_META_INFO &info, const QString &file) {
QFile f(file);
#define SEEK(address) \
if (!f.seek(address)) { \
f.close(); \
return false; \
}
if (!f.open(QIODevice::ReadOnly)) {
return false;
}
info.PEIndex = findIndexPE(f);
if (!info.PEIndex) {
return false;
}
SEEK(info.PEIndex + sizeof (unsigned int));
f.read(reinterpret_cast<char*>(&info.mashine), sizeof (info.mashine));
SEEK(info.PEIndex +
sizeof (unsigned int) +
sizeof (info.mashine));
f.read(reinterpret_cast<char*>(&info.rawSectionCount),
sizeof (info.rawSectionCount));
SEEK(info.PEIndex + INDEX_MAGIC);
unsigned short magic = 0x0;
f.read(reinterpret_cast<char*>(&magic), sizeof (magic));
info.type = magic;
unsigned int importTableIndex = 0;
if (static_cast<RunType>(info.type) == RunType::_32bit) {
importTableIndex = info.PEIndex + INDEX_IMPORTS_32;
} else if (static_cast<RunType>(info.type) == RunType::_64bit) {
importTableIndex = info.PEIndex + INDEX_IMPORTS_64;
} else {
f.close();
return false;
}
SEEK(importTableIndex);
IMAGE_DATA_DIRECTORY import = {};
f.read(reinterpret_cast<char*>(&import), sizeof (import));
QVector<IMAGE_SECTION_HEADER> sectionHeader;
if (!readSectionsHeaders(info, sectionHeader, f)) {
return false;
}
ROW_CONVERTER converter(sectionHeader, readSectionAligment(info, f));
info.addressImports = converter.convert(import.VirtualAddress);
info.sizeImportTable = import.Size;
f.close();
return true;
}
bool PE::is32bit(const QString &file, const LIB_META_INFO * info) {
if (!info) {
LIB_META_INFO meta;
if (!fillMetaInfo(meta, file)) {
return false;
}
return static_cast<RunType>(meta.type) == RunType::_32bit;
}
return static_cast<RunType>(info->type) == RunType::_32bit;
}
bool PE::dependecies(QStringList &list, const QString &file,
const LIB_META_INFO * info) {
LIB_META_INFO meta;
if (!info) {
if (!fillMetaInfo(meta, file)) {
return false;
}
} else {
meta = std::move(*info);
}
QFile f(file);
if (!f.open(QIODevice::ReadOnly)) {
return false;
}
if (!f.seek(meta.addressImports)) {
f.close();
return false;
}
auto data = f.read(meta.sizeImportTable).split(char(0x0));
f.close();
if (data.isEmpty()) {
return false;
}
for (QString i : data) {
if (i.contains(".dll")) {
list.push_back(i);
for ( auto &i : imports) {
if (!filter.count(i.moduleName)) {
filter.insert(i.moduleName);
res.push_back(QString::fromStdString(i.moduleName));
}
}
return true;
return res.size();
}
PE::PE(): IGetLibInfo () {
@ -214,24 +53,24 @@ PE::PE(): IGetLibInfo () {
}
bool PE::getLibInfo(const QString &lib, LibInfo &info) {
LIB_META_INFO meta;
auto parsedPeLib = peparse::ParsePEFromFile(lib.toLatin1());
if (!fillMetaInfo(meta, lib)) {
return false;
}
info.name = QFileInfo(lib).fileName();
info.path = QFileInfo(lib).absolutePath();
if (static_cast<RunType>(meta.type) == RunType::_32bit) {
if (static_cast<RunType>(parsedPeLib->peHeader.nt.OptionalMagic) == RunType::_32bit) {
info.platform = Platform::Win32;
} else if (static_cast<RunType>(meta.type) == RunType::_64bit) {
} else if (static_cast<RunType>(parsedPeLib->peHeader.nt.OptionalMagic) == RunType::_64bit) {
info.platform = Platform::Win64;
} else {
info.platform = Platform::UnknownPlatform;
}
dependecies(info.dependncies, lib, &meta);
info.name = QFileInfo(lib).fileName();
info.path = QFileInfo(lib).absolutePath();
if (!getDep(parsedPeLib->internal, info.dependncies)) {
return false;
}
peparse::DestructParsedPE(parsedPeLib);
return info.isValid();
}
@ -239,31 +78,3 @@ bool PE::getLibInfo(const QString &lib, LibInfo &info) {
PE::~PE(){
}
int ROW_CONVERTER::defSection(DWORD rva) {
for (int i = 0; i < sections.size(); ++i) {
DWORD start = sections[i].VirtualAddress;
DWORD end = start + ALIGN_UP(sections[i].VirtualSize, sectionAligment);
if(rva >= start && rva < end)
return i;
}
return -1;
}
DWORD ROW_CONVERTER::rvaToOff(DWORD rva) {
int indexSection = defSection(rva);
if(indexSection != -1)
return rva - sections[indexSection].VirtualAddress +
sections[indexSection].PointerToRawData;
else
return 0;
}
ROW_CONVERTER::ROW_CONVERTER(QVector<IMAGE_SECTION_HEADER> sctions, DWORD align) {
sections = sctions;
sectionAligment = align;
}
DWORD ROW_CONVERTER::convert(DWORD rva) {
return rvaToOff(rva);
}

@ -6,177 +6,16 @@
#include <QVector>
#include "igetlibinfo.h"
//Alghoritm of read dll file
//1. find PEMagic
//2. read magic
//3. check arhitecture (PE32 or PE32+)
//4. find on map of PE achitecture peraw addresses the address of section count
//5. find like point 4 address of begin sections headers
//6. read all sections or skip all sections and read only neaded information (rva addresses)
//7. read a size and rva address of import table and import table deley.
//8. convert rva addresses to raw addresses and jomp to begin import tables.
//9. read the all data of import tables and split it.
//10 find needed library of binary file.
struct LIB_META_INFO {
unsigned short mashine = 0x0;
unsigned short type = 0x0;
unsigned short PEIndex = 0x0;
unsigned short rawSectionCount = 0x0;
unsigned int addressImports = 0x0;
unsigned int sizeImportTable = 0x0;
};
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
#define IMAGE_SIZEOF_SHORT_NAME 8
// Directory Entries
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
#define ALIGN_DOWN(x, align) (x & ~(align-1))
#define ALIGN_UP(x, align) ((x & (align-1))?ALIGN_DOWN(x,align)+align:x)
// sectionAligment - выравнивание для секции. Значение можно узнать в Optional-header.
// sectionVitualAddress - RVA секции - хранится непосредственно в секции
// ALIGN_UP() - функция, определяющая сколько занимает секция в памяти, учитывая выравнивание
struct IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
};
struct IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
};
struct IMAGE_OPTIONAL_HEADER {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
};
struct IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER OptionalHeader;
};
struct IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
DWORD VirtualSize;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
};
class ROW_CONVERTER {
private:
int defSection(DWORD rva);
DWORD rvaToOff(DWORD rva);
QVector<IMAGE_SECTION_HEADER> sections;
DWORD sectionAligment;
public:
ROW_CONVERTER(QVector<IMAGE_SECTION_HEADER> sctions, DWORD align);
DWORD convert(DWORD rva);
};
namespace peparse {
struct parsed_pe_internal;
}
class PE : public IGetLibInfo {
private:
bool readSectionsHeaders(const LIB_META_INFO & info,
QVector<IMAGE_SECTION_HEADER> &sections,
QFile &file);
DWORD readSectionAligment(const LIB_META_INFO &info,
QFile &file);
unsigned short findIndexPE(QFile &file);
bool fillMetaInfo(LIB_META_INFO& info, const QString &file);
constexpr static unsigned int PE_MAGIC = 0x00004550;
constexpr static unsigned int INDEX_PE_MAGIC = 0x80;
constexpr static unsigned int INDEX_MAGIC = 0x18;
constexpr static unsigned int INDEX_IMPORTS_32 = 104;
constexpr static unsigned int INDEX_IMPORTS_64 = 120;
constexpr static unsigned int SECTION_HEADER_32 = 224;
constexpr static unsigned int SECTION_HEADER_64 = 240;
constexpr static unsigned int SECTION_ALIGMENT_INDEX_32_64 = 32;
bool getDep(peparse::parsed_pe_internal *, QStringList& res);
public:
enum class MashineTypesS: unsigned short {
IMAGE_FILE_MACHINE_UNKNOWN = 0x0,
IMAGE_FILE_MACHINE_AMD64 = 0x8664, // x64
IMAGE_FILE_MACHINE_ARM = 0x1c0, // ARM little endian
IMAGE_FILE_MACHINE_ARM64 = 0xaa64, // ARM64 little endian
IMAGE_FILE_MACHINE_ARMNT = 0x1c4, // ARM Thumb-2 little endian
IMAGE_FILE_MACHINE_I386 = 0x14c, // Intel 386 or later processors and compatible processors
};
enum class RunType: unsigned short {
_UNKNOWN = 0x0,
@ -184,10 +23,6 @@ public:
_64bit = 0x20B,
_ROM = 0x107,
};
bool is32bit(const QString& file, const LIB_META_INFO *info = nullptr);
bool dependecies(QStringList& lisr, const QString& file,
const LIB_META_INFO *info = nullptr);
PE();
bool getLibInfo(const QString& lib, LibInfo& info) override;

@ -17,6 +17,8 @@ CONFIG(release, debug|release): {
include('$$PWD/../QuasarAppLib/QuasarLib.pri')
include('$$PWD/../Deploy/Deploy.pri')
include('$$PWD/../pe/pe-parser-library/pe-parser.pri')
CONFIG += qt console warn_on depend_includepath testcase
CONFIG -= app_bundle

@ -66,7 +66,6 @@ void LibCreator::initLinux64() {
void LibCreator::initWin32() {
createLib(":/win32mingw.dll", {
"libEGL.dll",
"libgcc_s_dw2-1.dll",
"KERNEL32.dll",
"msvcrt.dll",
@ -74,15 +73,15 @@ void LibCreator::initWin32() {
},
Platform::Win32 );
createLib(":/win32mingw.exe",{
" Qt5Core.dll",
" Qt5Gui.dll",
" Qt5Qml.dll",
" Qt5Widgets.dll",
" libgcc_s_dw2-1.dll",
" KERNEL32.dll",
" msvcrt.dll",
" SHELL32.dll",
" libstdc++-6.dll",
"Qt5Core.dll",
"Qt5Gui.dll",
"Qt5Qml.dll",
"Qt5Widgets.dll",
"libgcc_s_dw2-1.dll",
"KERNEL32.dll",
"msvcrt.dll",
"SHELL32.dll",
"libstdc++-6.dll",
},
Platform::Win32
);

@ -302,7 +302,10 @@ void deploytest::testExtractLib() {
QVERIFY(info.path == QFileInfo(lib).absolutePath());
QVERIFY(info.fullPath() == QFileInfo(lib).absoluteFilePath());
QVERIFY(info.platform == platforms.value(lib));
QVERIFY(info.dependncies == deb.value(lib));
for (auto &dep : deb.value(lib)) {
QVERIFY(info.dependncies.contains( dep, Qt::CaseInsensitive));
}
}

1
pe Submodule

@ -0,0 +1 @@
Subproject commit 59c4c1c0de26b2173b4b406e26d601e7ed94896c