C++ 以编程方式获取用于在非开发人员Windows环境中构建进程或库的DLL列表

C++ 以编程方式获取用于在非开发人员Windows环境中构建进程或库的DLL列表,c++,windows,winapi,dependencies,C++,Windows,Winapi,Dependencies,我甚至不确定这是否适用于Windows;我从来没有见过一个人要求如此普遍的东西并找到解决办法。这可能是可能的,但可能没有处理它的API 我正在为Windows开发一个自动测试模块,它使用一个模块以通用方式处理检测到的EXE,除非它检测到二进制文件来自特定的测试框架。到目前为止,我只能通过查询帮助和处理响应/字符串解析来做到这一点。如果有人在接受命令行参数以获取帮助的框架之外编写了一个长测试,但实际上没有处理这些命令行参数,只是自动运行,那么这可能会导致问题。因此,有时我会在等待测试完成时陷入困境

我甚至不确定这是否适用于Windows;我从来没有见过一个人要求如此普遍的东西并找到解决办法。这可能是可能的,但可能没有处理它的API

我正在为Windows开发一个自动测试模块,它使用一个模块以通用方式处理检测到的EXE,除非它检测到二进制文件来自特定的测试框架。到目前为止,我只能通过查询帮助和处理响应/字符串解析来做到这一点。如果有人在接受命令行参数以获取帮助的框架之外编写了一个长测试,但实际上没有处理这些命令行参数,只是自动运行,那么这可能会导致问题。因此,有时我会在等待测试完成时陷入困境,而不是进行闪电般的查询。这正是我在这个新奇的新模块中试图避免的

这个问题的症结在于这个被消费的模块,用于获取DLL列表将被分发给非开发Windows系统,并且我不能用它(.NET,C++等)来说明它是如何构建的。这使我无法像Microsoft那样使用

dumpbin
link
。出于我自己的许可要求,我的此模块将不会出售;永远免费

在我意识到自己无法分发垃圾桶之前,有人建议我查看一下垃圾桶。当我使用它时,我得到的是:

c:\test_dir>dumpbin /dependents .\qt_unit_test.exe
唯一需要的信息是DLL依赖项列表。不需要同时使用动态库和静态库。最起码需要的是DLL,但如果有人能让我也使用静态库,那就太酷了;完全可选

我这样做基本上是为了验证它是否是Qt测试二进制文件:

c:\test_dir>dumpbin /dependents .\qt_unit_test.exe | call findstr /i qt5test 1>nul 2>nul
c:\test_dir>if "%errorlevel%"=="0" echo is Qt Test

编码方式,到目前为止我所尝试的是C的代码>汇编程序.GETRealCudieDebug程序> /Cudio>,但当然只得到程序集信息,所以常规的STL C++应用程序会产生异常。 下一步,我想尝试一些有意义的东西,但老实说,在WinAPI的土地上,我是一条水落石出的鱼。我可能误解了整个概念。。。无论如何,您可以检查当前代码,但我不知道如何将返回的

IntPtr
转换为一个字符串或字符串列表,告诉您使用了哪些DLL。看起来这是另一种方式,但是的,这里的经典场景

顺便说一句,我研究了使用的可能性,但是在你得到所有的工具后,这件事就结束了,这违背了我轻量级通用自动测试模块的目的

我愿意用任何语言来实现这一点;我从C++和C语言开始,因为我认为WiAPI访问可能会让我走出这个特定的OS。 更新: 6.4。.idata部分导入符号的所有图像文件,包括几乎所有可执行(EXE)文件,都有一个.idata部分。A. 导入信息的典型文件布局如下所示

在处理
.idata
表时,我遇到了一个棘手的小问题。
idata
部分的“几乎所有可执行文件…”子句并不像文档中所说的那样包罗万象。查看Windows 10的内置Calculator.exe应用程序:

.idata
部分。但是,这并不能阻止dumpbin查找这些依赖项:

更新#2: 在从我的一位导师那里得到了一些很好的建议和意见之后,离完成这项任务越来越近了。我成功地删除了所有需要调试库使用的Windows内部设备,或者在使用VisualC++运行时重置时,在GAC之外的LIBS。 当前的问题是从获取导入表的RVA到获取导入表中的所有名称。我的第一个查询导入提供了一个空名称,即使其余数据不是空的

//******************************************************************************
// HEADERS
#include "Windows.h"

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>

#include <experimental\filesystem>

//******************************************************************************
// NAMESPACES
namespace fs = std::experimental::filesystem;

//******************************************************************************
//FUNCTION DECLARATIONS
bool verify_image_file(std::string);
std::vector<char> read_all_bytes(const char* file);
std::vector<std::string> parse_file(std::string file);

//******************************************************************************
// CONSTANTS
//        LABEL                                                HEX            DEC
//
const WORD MAGIC_NUM_32BIT             = static_cast<const WORD>(0x10b);      // 267
const WORD MAGIC_NUM_64BIT             = static_cast<const WORD>(0x20b);      // 523
const int IMG_SIGNATURE_OFFSET         = static_cast<const int>(0x3c);        // 60
const int IMPORT_TABLE_OFFSET_32       = static_cast<const int>(0x68);        // 104
const int IMPORT_TABLE_OFFSET_64       = static_cast<const int>(0x78);        // 120
const int IMG_SIGNATURE_SIZE           = static_cast<const int>(0x4);         // 4
const int OPT_HEADER_OFFSET_32         = static_cast<const int>(0x1c);        // 28
const int OPT_HEADER_OFFSET_64         = static_cast<const int>(0x18);        // 24
const int DATA_DIR_OFFSET_32           = static_cast<const int>(0x60);        // 96
const int DATA_DIR_OFFSET_64           = static_cast<const int>(0x70);        // 112
const int DATA_IAT_OFFSET_64           = static_cast<const int>(0xD0);        // 208
const int DATA_IAT_OFFSET_32           = static_cast<const int>(0xC0);        // 192
const int SZ_OPT_HEADER_OFFSET         = static_cast<const int>(0x10);        // 16
const int RVA_AMOUNT_OFFSET_64         = static_cast<const int>(0x6c);        // 108
const int RVA_AMOUNT_OFFSET_32         = static_cast<const int>(0x5c);        // 92
const char * KNOWN_IMG_SIGNATURE       = static_cast<const char*>("PE\0\0");

//******************************************************************************
// Globals
bool is64Bit = false;
bool is32Bit = false;

//******************************************************************************
// PLACEHOLDERS
const char* ph_file("C:\\Windows\\System32\\notepad.exe");

//******************************************************************************
// ENTRY
int main(int argc, char* argv[])
{
    if (!verify_image_file(ph_file))return -1;

    if (parse_file(ph_file).size() > 1)return 0;
    else return -1;

    return -1;
}

//******************************************************************************
// FILE PARSER
std::vector<std::string> parse_file(std::string file)
{
    std::vector<char> bytes = read_all_bytes(file.c_str());
    std::vector<std::string> dependencies;

    DWORD * signature_offset_location = (DWORD*)&bytes[IMG_SIGNATURE_OFFSET];
    char * signature = (char*)&bytes[*signature_offset_location];

    if (*signature != *KNOWN_IMG_SIGNATURE)return dependencies;

    DWORD coff_file_header_offset = *signature_offset_location + IMG_SIGNATURE_SIZE;
    IMAGE_FILE_HEADER* coff_file_header = (IMAGE_FILE_HEADER*)&bytes[coff_file_header_offset];
    DWORD optional_file_header_offset = coff_file_header_offset + sizeof(IMAGE_FILE_HEADER);

    WORD size_of_optional_header_offset = coff_file_header_offset + SZ_OPT_HEADER_OFFSET;
    WORD* size_of_optional_header = (WORD*)&bytes[size_of_optional_header_offset];  

    //Magic is a 2-Byte value at offset-zero of the optional file header regardless of 32/64 bit
    WORD* magic_number = (WORD*)&bytes[optional_file_header_offset];

    if (*magic_number == MAGIC_NUM_32BIT)is32Bit = true;
    else if (*magic_number == MAGIC_NUM_64BIT)is64Bit = true;
    else
    {
        std::cerr << "Could not parse magic number for 32 or 64-bit PE-format Image File." << std::endl;
        return dependencies;
    }

    if (is64Bit)
    {
        IMAGE_OPTIONAL_HEADER64 * img_opt_header_64 = (IMAGE_OPTIONAL_HEADER64*)&bytes[optional_file_header_offset];
        IMAGE_DATA_DIRECTORY* import_table_data_dir = (IMAGE_DATA_DIRECTORY*)&bytes[optional_file_header_offset + IMPORT_TABLE_OFFSET_64];
        DWORD* import_table_address = (DWORD*)import_table_data_dir;



        // To Get the import table, you need to check all the IMAGE_SECTION_HEADERs for the section that matches size of the direct-query.
        // TO get those you can use normal offsets. To go further, we need to start using the RVA
        // IMAGE_SECTION_HEADERS starts directly after the end of the optional file header for file_header->NumberOfSections
        // Then, your RVA is if (ptr_to_raw_data >= va && ptr_to_raw_data < va + SizeOfData){//isSection}
        // DWORD FileOffset = Ptr_To_Raw_Data - VA + PointerToRawData


        DWORD image_section_header_offset = optional_file_header_offset;

        for (int i = 0; i < coff_file_header->NumberOfSections; i++)
        {
            IMAGE_SECTION_HEADER* queried_section_header = (IMAGE_SECTION_HEADER*)&bytes[image_section_header_offset];
            if  (queried_section_header->PointerToRawData >= import_table_data_dir->VirtualAddress && (queried_section_header->PointerToRawData < (import_table_data_dir->VirtualAddress + queried_section_header->SizeOfRawData)))
            {
                DWORD import_table_offset = queried_section_header->PointerToRawData - import_table_data_dir->VirtualAddress + queried_section_header->PointerToRawData;
                IMAGE_IMPORT_DESCRIPTOR* import_table_descriptor = (IMAGE_IMPORT_DESCRIPTOR*)&bytes[import_table_offset];
                if (import_table_descriptor->Name==NULL && 
                    import_table_descriptor->Characteristics==NULL &&
                    import_table_descriptor->FirstThunk==NULL &&
                    import_table_descriptor->ForwarderChain==NULL &&
                    import_table_descriptor->OriginalFirstThunk==NULL &&
                    import_table_descriptor->TimeDateStamp==NULL)
                {
                    break;//Signifies end of IMAGE_IMPORT_DESCRIPTORs
                }

                DWORD* dependency_name_address = (DWORD*)import_table_descriptor->Name;
                char * dependency_name = (char *)&bytes[import_table_descriptor->Name];
                dependencies.push_back((std::string)dependency_name);
                int breakpoint = 0;
            }
            image_section_header_offset = image_section_header_offset + sizeof(IMAGE_SECTION_HEADER);
        }
    }
    else//32-bit behavior
    {
        //todo
    }

    return dependencies;
}

//******************************************************************************
// FILE READER
std::vector<char> read_all_bytes(const char* filename)
{
    std::ifstream ifs(filename, std::ios::binary | std::ios::ate);
    std::ifstream::pos_type pos = ifs.tellg();

    std::vector<char> result(pos);
    ifs.seekg(0, std::ios::beg);
    ifs.read(&result[0], pos);

    return result;
}

//******************************************************************************
// IMAGE-TYPE FILE VERIFIER
bool verify_image_file(std::string file_to_verify)
{
    if (fs::exists(file_to_verify))
    {
        size_t extension_query = file_to_verify.find(".dll", 0);
        if (extension_query == std::string::npos)
        {
            extension_query = file_to_verify.find(".DLL", 0);
            if (extension_query == std::string::npos)
            {
                extension_query = file_to_verify.find(".exe", 0);
                if (extension_query == std::string::npos)
                {
                    extension_query = file_to_verify.find(".EXE", 0);
                }
                else { return true; }

                if (extension_query != std::string::npos) { return true; }
            }
            else { return true; }
        }
        else { return true; }
    }
    return false;
}
//******************************************************************************
//标题
#包括“Windows.h”
#包括
#包括
#包括
#包括
#包括
#包括
//******************************************************************************
//名称空间
命名空间fs=std::实验::文件系统;
//******************************************************************************
//函数声明
bool验证图像文件(std::string);
std::矢量读取所有字节(常量字符*文件);
std::vector parse_文件(std::string文件);
//******************************************************************************
//常数
//标签十六进制数字
//
常量单词MAGIC_NUM_32BIT=静态_cast(0x10b);//267
const WORD MAGIC_NUM_64BIT=static_cast(0x20b);//523
常量int IMG_SIGNATURE_OFFSET=static_cast(0x3c);//60
const int IMPORT_TABLE_OFFSET_32=static_cast(0x68);//104
const int IMPORT_TABLE_OFFSET_64=static_cast(0x78);//120
const int IMG_SIGNATURE_SIZE=static_cast(0x4);//4.
const int OPT_HEADER_OFFSET_32=static_cast(0x1c);//28
const int OPT_HEADER_OFFSET_64=static_cast(0x18);//24
常量int DATA_DIR_OFFSET_32=静态_cast(0x60);//96
常量int DATA_DIR_OFFSET_64=静态_cast(0x70);//112
常数int DATA_IAT_OFFSET_64=静态转换(0xD0);//208
常数int DATA_IAT_OFFSET_32=静态(0xC0);//192
const int SZ_OPT_HEADER_OFFSET=static_cast(0x10);//16
const int RVA_AMOUNT_OFFSET_64=静态强制转换(0x6c);//108
const int RVA_AMOUNT_OFFSET_32=static_cast(0x5c);//92
const char*KNOWN_IMG_SIGNATURE=static_cast(“PE\0\0”);
//******************************************************************************
//全球的
布尔是6岁
C:\WINDOWS\system32>dumpbin /summary "C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1703.601.0_x64__8wekyb3d8bbwe\Calculator.exe"

Microsoft (R) COFF/PE Dumper Version 14.00.24215.1
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1703.601.0_x64__8wekyb3d8bbwe\Calculator.exe

File Type: EXECUTABLE IMAGE

  Summary

       4C000 .data
        1000 .gfids
        1000 .giats
       21000 .pdata
      135000 .rdata
        A000 .reloc
        1000 .rsrc
      20D000 .text
        1000 .tls
        1000 minATL
C:\WINDOWS\system32>dumpbin /dependents "C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1703.601.0_x64__8wekyb3d8bbwe\Calculator.exe"
Microsoft (R) COFF/PE Dumper Version 14.00.24215.1
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1703.601.0_x64__8wekyb3d8bbwe\Calculator.exe

File Type: EXECUTABLE IMAGE

  Image has the following dependencies:

    api-ms-win-core-localization-l1-2-1.dll
    api-ms-win-eventing-provider-l1-1-0.dll
    api-ms-win-core-com-l1-1-1.dll
    api-ms-win-core-sysinfo-l1-2-1.dll
    api-ms-win-core-processthreads-l1-1-2.dll
    api-ms-win-core-sysinfo-l1-2-3.dll
    vccorlib140_app.DLL
    MSVCP140_APP.dll
    CONCRT140_APP.dll
    VCRUNTIME140_APP.dll
    api-ms-win-crt-runtime-l1-1-0.dll
    api-ms-win-crt-convert-l1-1-0.dll
    api-ms-win-crt-string-l1-1-0.dll
    api-ms-win-crt-heap-l1-1-0.dll
    api-ms-win-crt-stdio-l1-1-0.dll
    api-ms-win-crt-math-l1-1-0.dll
    api-ms-win-crt-locale-l1-1-0.dll
    api-ms-win-core-util-l1-1-0.dll
    api-ms-win-core-synch-l1-2-0.dll
    api-ms-win-core-winrt-error-l1-1-1.dll
    api-ms-win-core-winrt-string-l1-1-0.dll
    api-ms-win-core-handle-l1-1-0.dll
    api-ms-win-core-winrt-l1-1-0.dll
    api-ms-win-core-profile-l1-1-0.dll
    api-ms-win-core-libraryloader-l1-2-0.dll
    api-ms-win-core-interlocked-l1-2-0.dll

  Summary

       4C000 .data
        1000 .gfids
        1000 .giats
       21000 .pdata
      135000 .rdata
        A000 .reloc
        1000 .rsrc
      20D000 .text
        1000 .tls
        1000 minATL
//******************************************************************************
// HEADERS
#include "Windows.h"

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>

#include <experimental\filesystem>

//******************************************************************************
// NAMESPACES
namespace fs = std::experimental::filesystem;

//******************************************************************************
//FUNCTION DECLARATIONS
bool verify_image_file(std::string);
std::vector<char> read_all_bytes(const char* file);
std::vector<std::string> parse_file(std::string file);

//******************************************************************************
// CONSTANTS
//        LABEL                                                HEX            DEC
//
const WORD MAGIC_NUM_32BIT             = static_cast<const WORD>(0x10b);      // 267
const WORD MAGIC_NUM_64BIT             = static_cast<const WORD>(0x20b);      // 523
const int IMG_SIGNATURE_OFFSET         = static_cast<const int>(0x3c);        // 60
const int IMPORT_TABLE_OFFSET_32       = static_cast<const int>(0x68);        // 104
const int IMPORT_TABLE_OFFSET_64       = static_cast<const int>(0x78);        // 120
const int IMG_SIGNATURE_SIZE           = static_cast<const int>(0x4);         // 4
const int OPT_HEADER_OFFSET_32         = static_cast<const int>(0x1c);        // 28
const int OPT_HEADER_OFFSET_64         = static_cast<const int>(0x18);        // 24
const int DATA_DIR_OFFSET_32           = static_cast<const int>(0x60);        // 96
const int DATA_DIR_OFFSET_64           = static_cast<const int>(0x70);        // 112
const int DATA_IAT_OFFSET_64           = static_cast<const int>(0xD0);        // 208
const int DATA_IAT_OFFSET_32           = static_cast<const int>(0xC0);        // 192
const int SZ_OPT_HEADER_OFFSET         = static_cast<const int>(0x10);        // 16
const int RVA_AMOUNT_OFFSET_64         = static_cast<const int>(0x6c);        // 108
const int RVA_AMOUNT_OFFSET_32         = static_cast<const int>(0x5c);        // 92
const char * KNOWN_IMG_SIGNATURE       = static_cast<const char*>("PE\0\0");

//******************************************************************************
// Globals
bool is64Bit = false;
bool is32Bit = false;

//******************************************************************************
// PLACEHOLDERS
const char* ph_file("C:\\Windows\\System32\\notepad.exe");

//******************************************************************************
// ENTRY
int main(int argc, char* argv[])
{
    if (!verify_image_file(ph_file))return -1;

    if (parse_file(ph_file).size() > 1)return 0;
    else return -1;

    return -1;
}

//******************************************************************************
// FILE PARSER
std::vector<std::string> parse_file(std::string file)
{
    std::vector<char> bytes = read_all_bytes(file.c_str());
    std::vector<std::string> dependencies;

    DWORD * signature_offset_location = (DWORD*)&bytes[IMG_SIGNATURE_OFFSET];
    char * signature = (char*)&bytes[*signature_offset_location];

    if (*signature != *KNOWN_IMG_SIGNATURE)return dependencies;

    DWORD coff_file_header_offset = *signature_offset_location + IMG_SIGNATURE_SIZE;
    IMAGE_FILE_HEADER* coff_file_header = (IMAGE_FILE_HEADER*)&bytes[coff_file_header_offset];
    DWORD optional_file_header_offset = coff_file_header_offset + sizeof(IMAGE_FILE_HEADER);

    WORD size_of_optional_header_offset = coff_file_header_offset + SZ_OPT_HEADER_OFFSET;
    WORD* size_of_optional_header = (WORD*)&bytes[size_of_optional_header_offset];  

    //Magic is a 2-Byte value at offset-zero of the optional file header regardless of 32/64 bit
    WORD* magic_number = (WORD*)&bytes[optional_file_header_offset];

    if (*magic_number == MAGIC_NUM_32BIT)is32Bit = true;
    else if (*magic_number == MAGIC_NUM_64BIT)is64Bit = true;
    else
    {
        std::cerr << "Could not parse magic number for 32 or 64-bit PE-format Image File." << std::endl;
        return dependencies;
    }

    if (is64Bit)
    {
        IMAGE_OPTIONAL_HEADER64 * img_opt_header_64 = (IMAGE_OPTIONAL_HEADER64*)&bytes[optional_file_header_offset];
        IMAGE_DATA_DIRECTORY* import_table_data_dir = (IMAGE_DATA_DIRECTORY*)&bytes[optional_file_header_offset + IMPORT_TABLE_OFFSET_64];
        DWORD* import_table_address = (DWORD*)import_table_data_dir;



        // To Get the import table, you need to check all the IMAGE_SECTION_HEADERs for the section that matches size of the direct-query.
        // TO get those you can use normal offsets. To go further, we need to start using the RVA
        // IMAGE_SECTION_HEADERS starts directly after the end of the optional file header for file_header->NumberOfSections
        // Then, your RVA is if (ptr_to_raw_data >= va && ptr_to_raw_data < va + SizeOfData){//isSection}
        // DWORD FileOffset = Ptr_To_Raw_Data - VA + PointerToRawData


        DWORD image_section_header_offset = optional_file_header_offset;

        for (int i = 0; i < coff_file_header->NumberOfSections; i++)
        {
            IMAGE_SECTION_HEADER* queried_section_header = (IMAGE_SECTION_HEADER*)&bytes[image_section_header_offset];
            if  (queried_section_header->PointerToRawData >= import_table_data_dir->VirtualAddress && (queried_section_header->PointerToRawData < (import_table_data_dir->VirtualAddress + queried_section_header->SizeOfRawData)))
            {
                DWORD import_table_offset = queried_section_header->PointerToRawData - import_table_data_dir->VirtualAddress + queried_section_header->PointerToRawData;
                IMAGE_IMPORT_DESCRIPTOR* import_table_descriptor = (IMAGE_IMPORT_DESCRIPTOR*)&bytes[import_table_offset];
                if (import_table_descriptor->Name==NULL && 
                    import_table_descriptor->Characteristics==NULL &&
                    import_table_descriptor->FirstThunk==NULL &&
                    import_table_descriptor->ForwarderChain==NULL &&
                    import_table_descriptor->OriginalFirstThunk==NULL &&
                    import_table_descriptor->TimeDateStamp==NULL)
                {
                    break;//Signifies end of IMAGE_IMPORT_DESCRIPTORs
                }

                DWORD* dependency_name_address = (DWORD*)import_table_descriptor->Name;
                char * dependency_name = (char *)&bytes[import_table_descriptor->Name];
                dependencies.push_back((std::string)dependency_name);
                int breakpoint = 0;
            }
            image_section_header_offset = image_section_header_offset + sizeof(IMAGE_SECTION_HEADER);
        }
    }
    else//32-bit behavior
    {
        //todo
    }

    return dependencies;
}

//******************************************************************************
// FILE READER
std::vector<char> read_all_bytes(const char* filename)
{
    std::ifstream ifs(filename, std::ios::binary | std::ios::ate);
    std::ifstream::pos_type pos = ifs.tellg();

    std::vector<char> result(pos);
    ifs.seekg(0, std::ios::beg);
    ifs.read(&result[0], pos);

    return result;
}

//******************************************************************************
// IMAGE-TYPE FILE VERIFIER
bool verify_image_file(std::string file_to_verify)
{
    if (fs::exists(file_to_verify))
    {
        size_t extension_query = file_to_verify.find(".dll", 0);
        if (extension_query == std::string::npos)
        {
            extension_query = file_to_verify.find(".DLL", 0);
            if (extension_query == std::string::npos)
            {
                extension_query = file_to_verify.find(".exe", 0);
                if (extension_query == std::string::npos)
                {
                    extension_query = file_to_verify.find(".EXE", 0);
                }
                else { return true; }

                if (extension_query != std::string::npos) { return true; }
            }
            else { return true; }
        }
        else { return true; }
    }
    return false;
}
//******************************************************************************
// Headers
#include "Windows.h"

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>

#include <experimental\filesystem>

//******************************************************************************
// Namespaces
namespace fs = std::experimental::filesystem;

//******************************************************************************
//FUNCTION DECLARATIONS
bool verify_image_file(std::string);
std::vector<char> read_all_bytes(const char* file);
std::vector<std::string> parse_pe_import_table_names(std::string file);

//******************************************************************************
// Constants
//        LABEL                                                HEX            DEC
//
const WORD MAGIC_NUM_32BIT          = static_cast<const WORD>(0x10b);     // 267
const WORD MAGIC_NUM_64BIT          = static_cast<const WORD>(0x20b);     // 523
const int IMG_SIGNATURE_OFFSET      = static_cast<const int>(0x3c);       // 60
const int IMPORT_TABLE_OFFSET_32    = static_cast<const int>(0x68);       // 104
const int IMPORT_TABLE_OFFSET_64    = static_cast<const int>(0x78);       // 120
const int IMG_SIGNATURE_SIZE        = static_cast<const int>(0x4);        // 4
const int OPT_HEADER_OFFSET_32      = static_cast<const int>(0x1c);       // 28
const int OPT_HEADER_OFFSET_64      = static_cast<const int>(0x18);       // 24
const int DATA_DIR_OFFSET_32        = static_cast<const int>(0x60);       // 96
const int DATA_DIR_OFFSET_64        = static_cast<const int>(0x70);       // 112
const int DATA_IAT_OFFSET_64        = static_cast<const int>(0xD0);       // 208
const int DATA_IAT_OFFSET_32        = static_cast<const int>(0xC0);       // 192
const int SZ_OPT_HEADER_OFFSET      = static_cast<const int>(0x10);       // 16
const int RVA_AMOUNT_OFFSET_64      = static_cast<const int>(0x6c);       // 108
const int RVA_AMOUNT_OFFSET_32      = static_cast<const int>(0x5c);       // 92
const char * KNOWN_IMG_SIGNATURE    = static_cast<const char*>("PE\0\0");

//******************************************************************************
// Globals
bool is64Bit = false;
bool is32Bit = false;

//******************************************************************************
// Exceptions
class invalid_parameters        : public std::exception { const char* what() const throw()
{ return "You did not provide the solitary command-line parameter of the EXE or DLL to check.\n"; } };

class invalid_image_file        : public std::exception { const char* what() const throw()
{ return "The file detected was not determined to be an image file based off its extension.\n"; } };

class unexpected_rva_offset     : public std::exception { const char* what() const throw()
{ return "An unexpected value was returned for the RVA to File Offset.\n"; } };

class non_image_magic_number    : public std::exception { const char* what() const throw()
{ return "The PE Optional Header's Magic Number did not indicate the file was an image.\n"; } };

class invalid_pe_signature      : public std::exception { const char* what() const throw()
{ return "The PE Signature was not detected.\n"; } };

//******************************************************************************
// Entry
int main(int argc, char* argv[])
{
    if (argc != 2)throw invalid_parameters();

    const char* param_one = (const char*)argv[1];



    if (!verify_image_file(argv[1])) { throw invalid_image_file(); }

    std::vector<std::string> static_import_dependencies = parse_pe_import_table_names(argv[1]);
    if (static_import_dependencies.size() > 1)
    {
        for (int i = 0; i < (static_import_dependencies.size()-1);i++)
        {
            std::cout << static_import_dependencies[i] << std::endl;
        }
        return 0;
    }
    else return -1;

    return -1;
}

//******************************************************************************
// PE Parser
std::vector<std::string> parse_pe_import_table_names(std::string file)
{
    std::vector<char> bytes = read_all_bytes(file.c_str());
    std::vector<std::string> dependencies;

    DWORD * signature_offset_location = (DWORD*)&bytes[IMG_SIGNATURE_OFFSET];
    char * signature = (char*)&bytes[*signature_offset_location];

    if (*signature != *KNOWN_IMG_SIGNATURE)return dependencies;

    DWORD coff_file_header_offset = *signature_offset_location + IMG_SIGNATURE_SIZE;
    IMAGE_FILE_HEADER* coff_file_header = (IMAGE_FILE_HEADER*)&bytes[coff_file_header_offset];
    DWORD optional_file_header_offset = coff_file_header_offset + sizeof(IMAGE_FILE_HEADER);

    WORD size_of_optional_header_offset = coff_file_header_offset + SZ_OPT_HEADER_OFFSET;
    WORD* size_of_optional_header = (WORD*)&bytes[size_of_optional_header_offset];

    //Magic is a 2-Byte value at offset-zero of the optional file header regardless of 32/64 bit
    WORD* magic_number = (WORD*)&bytes[optional_file_header_offset];

    if (*magic_number == MAGIC_NUM_32BIT)is32Bit = true;
    else if (*magic_number == MAGIC_NUM_64BIT)is64Bit = true;
    else
    {
        std::cerr << "Could not parse magic number for 32 or 64-bit PE-format Image File." << std::endl;
        return dependencies;
    }

    if (is64Bit)
    {
        IMAGE_OPTIONAL_HEADER64 * img_opt_header_64 = (IMAGE_OPTIONAL_HEADER64*)&bytes[optional_file_header_offset];
        IMAGE_DATA_DIRECTORY* import_table_data_dir = (IMAGE_DATA_DIRECTORY*)&bytes[optional_file_header_offset + IMPORT_TABLE_OFFSET_64];
        DWORD* import_table_address = (DWORD*)import_table_data_dir;

        DWORD image_section_header_offset = optional_file_header_offset + coff_file_header->SizeOfOptionalHeader;

        for (int i = 0; i < coff_file_header->NumberOfSections; i++)
        {
            IMAGE_SECTION_HEADER* queried_section_header = (IMAGE_SECTION_HEADER*)&bytes[image_section_header_offset];
            if (*import_table_address >= queried_section_header->VirtualAddress &&
                (*import_table_address < (queried_section_header->VirtualAddress + queried_section_header->SizeOfRawData)))
            {
                DWORD import_table_offset = *import_table_address - queried_section_header->VirtualAddress + queried_section_header->PointerToRawData;
                while(true)
                {
                    IMAGE_IMPORT_DESCRIPTOR* import_table_descriptor = (IMAGE_IMPORT_DESCRIPTOR*)&bytes[import_table_offset];
                    if (import_table_descriptor->OriginalFirstThunk == 0)
                    {
                        break;//Signifies end of IMAGE_IMPORT_DESCRIPTORs
                    }
                    // (VA from data directory _entry_ to Image Import Descriptor's element you want) - VA from section header + section header's PointerToRawData
                    DWORD dependency_name_address = import_table_descriptor->Name;//VA not RVA; ABSOLUTE
                    DWORD name_offset = dependency_name_address - queried_section_header->VirtualAddress + queried_section_header->PointerToRawData;
                    char * dependency_name = (char *)&bytes[name_offset];
                    dependencies.push_back((std::string)dependency_name);
                    import_table_offset = import_table_offset + sizeof(IMAGE_IMPORT_DESCRIPTOR);
                }
            }
            image_section_header_offset = image_section_header_offset + sizeof(IMAGE_SECTION_HEADER);
        }
    }
    else//32-bit behavior
    {
        IMAGE_OPTIONAL_HEADER32 * img_opt_header_32 = (IMAGE_OPTIONAL_HEADER32*)&bytes[optional_file_header_offset];
        IMAGE_DATA_DIRECTORY* import_table_data_dir = (IMAGE_DATA_DIRECTORY*)&bytes[optional_file_header_offset + IMPORT_TABLE_OFFSET_32];
        DWORD* import_table_address = (DWORD*)import_table_data_dir;

        DWORD image_section_header_offset = optional_file_header_offset + coff_file_header->SizeOfOptionalHeader;

        for (int i = 0; i < coff_file_header->NumberOfSections; i++)
        {
            IMAGE_SECTION_HEADER* queried_section_header = (IMAGE_SECTION_HEADER*)&bytes[image_section_header_offset];
            if (*import_table_address >= queried_section_header->VirtualAddress &&
                (*import_table_address < (queried_section_header->VirtualAddress + queried_section_header->SizeOfRawData)))
            {
                DWORD import_table_offset = *import_table_address - queried_section_header->VirtualAddress + queried_section_header->PointerToRawData;
                while (true)
                {
                    IMAGE_IMPORT_DESCRIPTOR* import_table_descriptor = (IMAGE_IMPORT_DESCRIPTOR*)&bytes[import_table_offset];
                    if (import_table_descriptor->OriginalFirstThunk == 0)
                    {
                        break;//Signifies end of IMAGE_IMPORT_DESCRIPTORs
                    }
                    // (VA from data directory _entry_ to Image Import Descriptor's element you want) - VA from section header + section header's PointerToRawData
                    DWORD dependency_name_address = import_table_descriptor->Name;//VA not RVA; ABSOLUTE
                    DWORD name_offset = dependency_name_address - queried_section_header->VirtualAddress + queried_section_header->PointerToRawData;
                    char * dependency_name = (char *)&bytes[name_offset];
                    dependencies.push_back((std::string)dependency_name);
                    import_table_offset = import_table_offset + sizeof(IMAGE_IMPORT_DESCRIPTOR);
                }
            }
            image_section_header_offset = image_section_header_offset + sizeof(IMAGE_SECTION_HEADER);
        }
    }

    return dependencies;
}

//******************************************************************************
// File Reader
std::vector<char> read_all_bytes(const char* filename)
{
    std::ifstream ifs(filename, std::ios::binary | std::ios::ate);
    std::ifstream::pos_type pos = ifs.tellg();

    std::vector<char> result(pos);
    ifs.seekg(0, std::ios::beg);
    ifs.read(&result[0], pos);

    return result;
}

//******************************************************************************
// IMAGE-TYPE FILE VERIFIER
bool verify_image_file(std::string file_to_verify)
{
    if (fs::exists(file_to_verify))
    {
        size_t extension_query = file_to_verify.find(".dll", 0);
        if (extension_query == std::string::npos)
        {
            extension_query = file_to_verify.find(".DLL", 0);
            if (extension_query == std::string::npos)
            {
                extension_query = file_to_verify.find(".exe", 0);
                if (extension_query == std::string::npos)
                {
                    extension_query = file_to_verify.find(".EXE", 0);
                }
                else { return true; }

                if (extension_query != std::string::npos) { return true; }
            }
            else { return true; }
        }
        else { return true; }
    }
    return false;
}