一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - C/C++ - C++ 實(shí)現(xiàn)PE文件特征碼識(shí)別的步驟

C++ 實(shí)現(xiàn)PE文件特征碼識(shí)別的步驟

2021-11-17 15:15lyshark C/C++

PE文件就是我們常說的EXE可執(zhí)行文件,針對(duì)文件特征的識(shí)別可以清晰的知道該程序是使用何種編程語言實(shí)現(xiàn)的,前提是要有特征庫,PE特征識(shí)別有多種形式,第一種是靜態(tài)識(shí)別,第二種則是動(dòng)態(tài)識(shí)別,我們經(jīng)常使用的PEID查殼工具是基

打開PE文件映射:

在讀取PE結(jié)構(gòu)之前,首先要做的就是打開PE文件到內(nèi)存,這里打開文件我們使用了CreateFile()函數(shù)該函數(shù)可以打開文件并返回文件句柄,接著使用CreateFileMapping()函數(shù)創(chuàng)建文件的內(nèi)存映像,最后使用MapViewOfFile()讀取映射中的內(nèi)存并返回一個(gè)句柄,后面的程序就可以通過該句柄操作打開后的文件了.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#include <Windows.h>
#include <ImageHlp.h>
 
#pragma comment(lib,"Imagehlp.lib")
 
// 讀取PE結(jié)構(gòu)的封裝
HANDLE OpenPeFile(LPTSTR FileName)
{
    HANDLE hFile, hMapFile, lpMapAddress = NULL;
    DWORD dwFileSize = 0;
 
    // CreateFile 既可以創(chuàng)建文件,也可以打開文件,這里則是打開文件的含義
    hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        return 0;
 
    // 獲取到文件大小
    dwFileSize = GetFileSize(hFile, NULL);
 
    // 創(chuàng)建文件的內(nèi)存映像
    // 此方法非常靈活,其不需要將程序完全讀入內(nèi)存中,節(jié)約空間。
    hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL);
    if (hMapFile == NULL)
        return 0;
 
    // 讀取映射中的內(nèi)存并返回一個(gè)句柄
    lpMapAddress = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, dwFileSize);
    if (lpMapAddress != NULL)
        return lpMapAddress;
    return 0;
}
 
int main(int argc, char * argv[])
{
    HANDLE lpMapAddress = NULL;
 
    lpMapAddress = OpenPeFile("c://lyshark.exe");
    printf("打開文件句柄: %d \n", lpMapAddress);
 
    system("pause");
    return 0;
}

判斷是否為PE文件:

當(dāng)文件已經(jīng)打開后,接下來就要判斷文件是否為有效的PE文件,這里我們首先將鏡像轉(zhuǎn)換為PIMAGE_DOS_HEADER格式并通過pDosHead->e_magic屬性找到PIMAGE_NT_HEADERS結(jié)構(gòu),然后判斷其是否符合PE文件規(guī)范即可,這里需要注意32位于64位PE結(jié)構(gòu)所使用的的結(jié)構(gòu)定義略有不同,代碼中已經(jīng)對(duì)其進(jìn)行了區(qū)分.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <stdio.h>
#include <Windows.h>
#include <ImageHlp.h>
 
#pragma comment(lib,"Imagehlp.lib")
 
// 讀取PE結(jié)構(gòu)的封裝
HANDLE OpenPeFile(LPTSTR FileName)
{
    HANDLE hFile, hMapFile, lpMapAddress = NULL;
    DWORD dwFileSize = 0;
 
    // CreateFile 既可以創(chuàng)建文件,也可以打開文件,這里則是打開文件的含義
    hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        return 0;
 
    // 獲取到文件大小
    dwFileSize = GetFileSize(hFile, NULL);
 
    // 創(chuàng)建文件的內(nèi)存映像
    // 此方法非常靈活,其不需要將程序完全讀入內(nèi)存中,節(jié)約空間。
    hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL);
    if (hMapFile == NULL)
        return 0;
 
    // 讀取映射中的內(nèi)存并返回一個(gè)句柄
    lpMapAddress = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, dwFileSize);
    if (lpMapAddress != NULL)
        return lpMapAddress;
    return 0;
}
 
// 判斷是否為PE文件
BOOL IsPeFile(HANDLE ImageBase, BOOL Is64 = FALSE)
{
    PIMAGE_DOS_HEADER pDosHead = NULL;
    if (ImageBase == NULL)
        return FALSE;
 
    // 將映射文件轉(zhuǎn)為DOS結(jié)構(gòu),并判斷開頭是否為MZ
    pDosHead = (PIMAGE_DOS_HEADER)ImageBase;
    if (IMAGE_DOS_SIGNATURE != pDosHead->e_magic)
        return FALSE;
 
    if (Is64 == TRUE)
    {
        // 根據(jù) IMAGE_DOS_HEADER 的 e_lfanew 的值得到 64位 NT 頭的位置
        PIMAGE_NT_HEADERS64 pNtHead64 = NULL;
        pNtHead64 = (PIMAGE_NT_HEADERS64)((DWORD64)pDosHead + pDosHead->e_lfanew);
        if (pNtHead64->Signature != IMAGE_NT_SIGNATURE)
            return FALSE;
    }
    else if (Is64 == FALSE)
    {
        // 根據(jù) IMAGE_DOS_HEADER 的 e_lfanew 的值得到 32位 NT 頭的位置
        PIMAGE_NT_HEADERS pNtHead32 = NULL;
        pNtHead32 = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
        if (pNtHead32->Signature != IMAGE_NT_SIGNATURE)
            return FALSE;
    }
    return TRUE;
}
 
int main(int argc, char * argv[])
{
    HANDLE lpMapAddress = NULL;
 
    // 打開文件拿到PE句柄
    lpMapAddress = OpenPeFile("c://lyshark.exe");
 
    // 判斷是否為PE文件,這里定義的為真返回1,為假返回0
    BOOL ret = IsPeFile(lpMapAddress, 0);
    printf("是否為PE文件: %d \n", ret);
 
    system("pause");
    return 0;
}

判斷PE文件特征碼:

判斷程序使用了何種編譯器編寫,通常情況是要用文件的入口處代碼和特征碼進(jìn)行匹配,通常情況下我們只需要匹配程序開頭的前32個(gè)字節(jié)就差不多了,當(dāng)然為了匹配精度更高,我們也可以對(duì)多個(gè)字段進(jìn)行驗(yàn)證,這里就只寫出大體輪廓吧.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <stdio.h>
#include <Windows.h>
#include <ImageHlp.h>
 
#pragma comment(lib,"Imagehlp.lib")
 
// 讀取PE結(jié)構(gòu)的封裝
HANDLE OpenPeFile(LPTSTR FileName)
{
    HANDLE hFile, hMapFile, lpMapAddress = NULL;
    DWORD dwFileSize = 0;
 
    // CreateFile 既可以創(chuàng)建文件,也可以打開文件,這里則是打開文件的含義
    hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        return 0;
 
    // 獲取到文件大小
    dwFileSize = GetFileSize(hFile, NULL);
 
    // 創(chuàng)建文件的內(nèi)存映像
    // 此方法非常靈活,其不需要將程序完全讀入內(nèi)存中,節(jié)約空間。
    hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL);
    if (hMapFile == NULL)
        return 0;
 
    // 讀取映射中的內(nèi)存并返回一個(gè)句柄
    lpMapAddress = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, dwFileSize);
    if (lpMapAddress != NULL)
        return lpMapAddress;
    return 0;
}
 
// 判斷是否為PE文件
BOOL IsPeFile(HANDLE ImageBase, BOOL Is64 = FALSE)
{
    PIMAGE_DOS_HEADER pDosHead = NULL;
    if (ImageBase == NULL)
        return FALSE;
 
    // 將映射文件轉(zhuǎn)為DOS結(jié)構(gòu),并判斷開頭是否為MZ
    pDosHead = (PIMAGE_DOS_HEADER)ImageBase;
    if (IMAGE_DOS_SIGNATURE != pDosHead->e_magic)
        return FALSE;
 
    if (Is64 == TRUE)
    {
        // 根據(jù) IMAGE_DOS_HEADER 的 e_lfanew 的值得到 64位 NT 頭的位置
        PIMAGE_NT_HEADERS64 pNtHead64 = NULL;
        pNtHead64 = (PIMAGE_NT_HEADERS64)((DWORD64)pDosHead + pDosHead->e_lfanew);
        if (pNtHead64->Signature != IMAGE_NT_SIGNATURE)
            return FALSE;
    }
    else if (Is64 == FALSE)
    {
        // 根據(jù) IMAGE_DOS_HEADER 的 e_lfanew 的值得到 32位 NT 頭的位置
        PIMAGE_NT_HEADERS pNtHead32 = NULL;
        pNtHead32 = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
        if (pNtHead32->Signature != IMAGE_NT_SIGNATURE)
            return FALSE;
    }
    return TRUE;
}
 
// 掃描特征碼,對(duì)比
void GetPeSignature(LPCWSTR FilePath)
{
    typedef struct _SIGN
    {
        char FileName[64];         // 存儲(chǔ)文件名或特征描述
        LONG FileOffset;           // 存儲(chǔ)檢測(cè)文件偏移地址
        BYTE VirusSign[32 + 1];    // 存儲(chǔ)特征碼大小32,其中的1是結(jié)束符.
    }SIGN, *pSIGN;
 
    // 定義特征碼與特征描述信息,你可以自己去提取一段特征碼
    SIGN Sign[2] = {
        {
            "Microsoft Visual C/C++ x86 (2013)",
            0x8a0,
        "\x55\x8B\xEC\x81\xEC\xC4\x00\x00\x00\x53\x56\x57\x8D\xBD\x3C\xFF" \
        "\xFF\xFF\xB9\x31\x00\x00\x00\xB8\xCC\xCC\xCC\xCC\xF3\xAB\x8B\x45" \
        },
        {
            "Microsoft Visual C/C++ x64 (2013)",
            0x400,
        "\xCC\xCC\xCC\xCC\xCC\xE9\x86\x02\x00\x00\xE9\x31\x05\x00\x00\xE9" \
        "\x6C\x01\x00\x00\xE9\x57\x03\x00\x00\xE9\x22\x00\x00\x00\xCC\xCC" \
        }
    };
 
    DWORD dwNum = 0;
    BYTE buffer[32 + 1];
    HANDLE hFile = NULL;
 
    // 獲取到FilePath路徑下文件的句柄信息
    hFile = CreateFile(FilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 
    // 我們有兩段待檢測(cè)特征,這里循環(huán)兩次從零開始
    for (int x = 0; x <= 2; x++)
    {
        // 將待檢測(cè)程序的文件指針指向特征碼的偏移位置
        SetFilePointer(hFile, Sign[x].FileOffset, NULL, FILE_BEGIN);
        // 讀取目標(biāo)程序指定位置的特征碼到內(nèi)存中
        ReadFile(hFile, buffer, sizeof(buffer), &dwNum, NULL);
        // 對(duì)比內(nèi)存中兩個(gè)特征碼是否相等
        if (memcmp(Sign[x].VirusSign, buffer, 32) == 0)
        {
            printf("檢測(cè)結(jié)果: %s \n", Sign[x].FileName);
        }
    }
    CloseHandle(hFile);
}
 
int main(int argc, char * argv[])
{
    GetPeSignature(L"c://lyshark.exe");
    system("pause");
    return 0;
}

你需要自己提取不同編譯器的特征字段,然后按照我寫好的格式進(jìn)行增加,例如我是用vs2013編譯的,那么檢測(cè)結(jié)果就可能會(huì)是vs2013,特征碼的提取應(yīng)盡量保證一致性。

C++ 實(shí)現(xiàn)PE文件特征碼識(shí)別的步驟

文章出處:https://www.cnblogs.com/lyshark

以上就是C++ 實(shí)現(xiàn)PE文件特征碼識(shí)別的步驟的詳細(xì)內(nèi)容,更多關(guān)于C++ PE文件特征碼識(shí)別的資料請(qǐng)關(guān)注服務(wù)器之家其它相關(guān)文章!

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产精品久久久久久久午夜片 | 香蕉 在线播放 | 国内小情侣一二三区在线视频 | pregnant欧美孕交xxx | 久久久高清国产999尤物 | 精品国产成人高清在线 | 免费日本视频 | 国产成人手机在线 | 日日艹 | 青草视频网站在线观看 | 婷婷综合久久中文字幕 | 热99这里只有精品 | 国产91精选学生在线观看 | 男生和老师一起差差差 | 国产欧美成人不卡视频 | 青草国产福利视频免费观看 | 精品视频一区二区三区免费 | 日本久久免费大片 | 午夜看片a福利在线观看 | 日本理论片中文在线观看2828 | 果冻传媒 天美 麻豆 | 日日插插 | youjizzxxx在线观看 | 久久婷婷五月综合色精品首页 | 小草视频免费观看在线 | 色色色色色色网 | 麻豆网| 国产精品综合在线 | 日韩精品一区二三区中文 | 九九九九九九伊人 | 91看片淫黄大片在看 | 日韩美毛片 | 男人最爱看的网站 | 日本国产高清色www视频在线 | 国产国语在线播放视频 | 亚洲第一区二区快射影院 | 天堂a免费视频在线观看 | 国产综合成人久久大片91 | 午夜一级影院 | 天天曰天天干 | 窝窝午夜理伦影院 |