吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2470|回复: 5
收起左侧

[C&C++ 原创] 【VC】【笔记】自写vmp壳子编写报告(二)

[复制链接]
舒默哦 发表于 2020-9-30 18:35



前言:
这是虚拟机笔记的最后一章,主要说明IAT加密,随机花指令构造器,反调试等
可以新建一个动态库(Stub.dll)作为外壳,来处理虚拟机、IAT加密,以及随机花指令构造器等等的一些信息




0x00、IAT加密
第一步
首先把IAT表转存到一个临时数据结构中,然后清除IAT和INT表,最后把临时数据结构中的函数名称加密,等待下一步处理。
[C++] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//保存IAT表
void Pack::SaveImportTab(char* m_pFileBuf)
{
    //0.获取导入表结构体指针
    PE pe;
    DWORD Virtual = pe.GET_HEADER_DICTIONARY((ULONG_PTR)m_pFileBuf, 1);
    if (Virtual == 0)
    {
        return;
    }
    PIMAGE_IMPORT_DESCRIPTOR pPEImport = (PIMAGE_IMPORT_DESCRIPTOR)(Virtual + m_pFileBuf);
    //1.第一遍循环确定 m_pModNameBuf 和 m_pFunNameBuf 的大小
    DWORD dwSizeOfModBuf = 0;
    DWORD dwSizeOfFunBuf = 0;
    m_dwNumOfIATFuns = 0;
    while (pPEImport->Name)
    {
        DWORD dwModNameRVA = pPEImport->Name;
        char* pModName = (char*)(m_pFileBuf + dwModNameRVA);
        dwSizeOfModBuf += (strlen(pModName) + 1);
 
        PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)(m_pFileBuf + pPEImport->FirstThunk);
 
        while (pIAT->u1.AddressOfData)
        {
            if (IMAGE_SNAP_BY_ORDINAL(pIAT->u1.Ordinal))
            {
                m_dwNumOfIATFuns++;
            }
            else
            {
                m_dwNumOfIATFuns++;
                ULONG_PTR dwFunNameRVA = pIAT->u1.AddressOfData;
                PIMAGE_IMPORT_BY_NAME pstcFunName = (PIMAGE_IMPORT_BY_NAME)(m_pFileBuf + dwFunNameRVA);
                dwSizeOfFunBuf += (strlen(pstcFunName->Name) + 1);
            }
            pIAT++;
        }
        pPEImport++;
    }
 
    //2.第二遍循环保存信息
 
    //申请内存保存IAT表信息
    m_pModNameBuf = m_allocMemory.auto_malloc<PVOID>(dwSizeOfModBuf);
    m_pFunNameBuf = m_allocMemory.auto_malloc<PVOID>(dwSizeOfFunBuf);
    m_pMyImport = m_allocMemory.auto_malloc<PMYIMPORT>(m_dwNumOfIATFuns * sizeof(MYIMPORT));
 
 
    pPEImport = (PIMAGE_IMPORT_DESCRIPTOR)(Virtual + m_pFileBuf);
    ULONG_PTR TempNumOfFuns = 0;
    ULONG_PTR TempModRVA = 0;
    ULONG_PTR TempFunRVA = 0;
    while (pPEImport->Name)
    {
        DWORD dwModNameRVA = pPEImport->Name;
        char* pModName = (char*)(m_pFileBuf + dwModNameRVA);
        memcpy_s((PCHAR)m_pModNameBuf + TempModRVA, strlen(pModName) + 1,
            pModName, strlen(pModName) + 1);
 
        PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)(m_pFileBuf + pPEImport->FirstThunk);
 
        while (pIAT->u1.AddressOfData)
        {
            if (IMAGE_SNAP_BY_ORDINAL(pIAT->u1.Ordinal))
            {
                //保存以序号出方式的函数信息
                m_pMyImport[TempNumOfFuns].m_dwIATAddr = (ULONG_PTR)pIAT - (ULONG_PTR)m_pFileBuf;
                m_pMyImport[TempNumOfFuns].m_bIsOrdinal = TRUE;
#ifdef _WIN64
                m_pMyImport[TempNumOfFuns].m_Ordinal = pIAT->u1.Ordinal & 0x7FFFFFFFFFFFFFFF;
#else
                m_pMyImport[TempNumOfFuns].m_Ordinal = pIAT->u1.Ordinal & 0x7FFFFFFF;
#endif // DEBUG
 
                m_pMyImport[TempNumOfFuns].m_dwModNameRVA = TempModRVA;
            }
            else
            {
                //保存名称号出方式的函数信息
                m_pMyImport[TempNumOfFuns].m_dwIATAddr = (ULONG_PTR)pIAT - (ULONG_PTR)m_pFileBuf;
 
                ULONG_PTR dwFunNameRVA = pIAT->u1.AddressOfData;
                PIMAGE_IMPORT_BY_NAME pstcFunName = (PIMAGE_IMPORT_BY_NAME)(m_pFileBuf + dwFunNameRVA);
                memcpy_s((PCHAR)m_pFunNameBuf + TempFunRVA, strlen(pstcFunName->Name) + 1,
                    pstcFunName->Name, strlen(pstcFunName->Name) + 1);
 
                m_pMyImport[TempNumOfFuns].m_dwFunNameRVA = TempFunRVA;
                m_pMyImport[TempNumOfFuns].m_dwModNameRVA = TempModRVA;
                TempFunRVA += (strlen(pstcFunName->Name) + 1);
            }
            TempNumOfFuns++;
            pIAT++;
        }
        TempModRVA += (strlen(pModName) + 1);
        pPEImport++;
    }
 
    //逆序排列m_pMyImport
    MYIMPORT stcTemp = { 0 };
    DWORD dwTempNum = m_dwNumOfIATFuns / 2;
    for (DWORD i = 0; i < dwTempNum; i++)
    {
        m_pMyImport[i];
        m_pMyImport[m_dwNumOfIATFuns - i - 1];
        memcpy_s(&stcTemp, sizeof(MYIMPORT), &m_pMyImport[i], sizeof(MYIMPORT));
        memcpy_s(&m_pMyImport[i], sizeof(MYIMPORT), &m_pMyImport[m_dwNumOfIATFuns - i - 1], sizeof(MYIMPORT));
        memcpy_s(&m_pMyImport[m_dwNumOfIATFuns - i - 1], sizeof(MYIMPORT), &stcTemp, sizeof(MYIMPORT));
    }
 
    //保存信息
    m_dwSizeOfModBuf = dwSizeOfModBuf;
    m_dwSizeOfFunBuf = dwSizeOfFunBuf;
}

[C++] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
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
//清除IAT表
void Pack::ClearImportTab(char* m_pFileBuf)
{
    PE pe;
    DWORD DirData = pe.GET_HEADER_DICTIONARY((ULONG_PTR)m_pFileBuf, 1);
    //1、获取导入表结构体指针
    PIMAGE_IMPORT_DESCRIPTOR pPEImport =
        (PIMAGE_IMPORT_DESCRIPTOR)(m_pFileBuf + DirData);
 
    //2.开始循环抹去IAT(导入表)数据
    //每循环一次抹去一个Dll的所有导入信息
    while (pPEImport->Name)
    {
        //2.1.抹去模块名
        DWORD dwModNameRVA = pPEImport->Name;
        char* pModName = (char*)(m_pFileBuf + dwModNameRVA);
        memset(pModName, 0, strlen(pModName));
 
        PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)(m_pFileBuf + pPEImport->FirstThunk);
        PIMAGE_THUNK_DATA pINT = (PIMAGE_THUNK_DATA)(m_pFileBuf + pPEImport->OriginalFirstThunk);
 
        //2.2. 抹去IAT、INT和函数名函数序号
        while (pIAT->u1.AddressOfData)
        {
            //判断是输出函数名还是序号
            if (IMAGE_SNAP_BY_ORDINAL(pIAT->u1.Ordinal))
            {
                //抹去序号就是将pIAT清空
            }
            else
            {
                //输出函数名
                ULONG_PTR dwFunNameRVA = pIAT->u1.AddressOfData;
                PIMAGE_IMPORT_BY_NAME pstcFunName = (PIMAGE_IMPORT_BY_NAME)(m_pFileBuf + dwFunNameRVA);
                //清除函数名和函数序号
                memset(pstcFunName, 0, strlen(pstcFunName->Name) + sizeof(WORD));
            }
            memset(pINT, 0, sizeof(IMAGE_THUNK_DATA));
            memset(pIAT, 0, sizeof(IMAGE_THUNK_DATA));
            pINT++;
            pIAT++;
        }
 
        //2.3.抹去导入表目录信息
        memset(pPEImport, 0, sizeof(IMAGE_IMPORT_DESCRIPTOR));
 
        //遍历下一个模块
        pPEImport++;
    }
 
}



第二步
把加密的IAT的表,放到虚拟机中解密,最后跳到花指令处,每次启动程序,
花指令都是不一样的(就像每次启动程序进入虚拟机,地址都是打乱的一样),然后解密,最终跳到要去的地方。
clipboard.png
[C++] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
//处理IAT表的handler就几行代码,当然还可以等价变形
void IATEncypt(char* VR0,char* VR1)
{
    CString str = "";
    str = str + "mov " + VR0 + ",ebp\n";
    str = str + "mov " + VR0 + ",dword ptr[" + VR0 + "]\n";
    //str = str + "xor " + VR0 + "," + 密钥;      //第1次解密
    //str = str + "add " + VR0 + "," + 密钥;      //第2次解密
    //str = str + "xor " + VR0 + "," + 密钥;      //第3次解密
    //str = str + "sub " + VR0 + "," + 密钥;      //第4次解密
    str = str + "popfd\n";
    str = str + "popad\n";
    str = str + "jmp " + VR0 + "\n"; //跳到花指处
}




0x01、随机花指令构造器
构造花指令,可以使用无条件跳转,比如ret、call、jmp来跳转,也可以使用有条件跳转,跳转的越多,能给人造成的困扰越大。
下面的是一个随机花指令构造器,很简单,只有一跳,每调用一次srandjunkcode()就会构造出一条花指令。
当然,可以构造出一个多跳、往回跳、来回往复的花指令机器,并把关键数据插入其中。
[C++] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
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
char jncode_one= 0xEB;
char jncode[0x4] = { 0xE8,0xE9,0xFF,0xEB };
 
char second[0x2] = { 0x15,0x25 };
char jmpoep[7] = { 0xb8,0x90,0x90,0x90,0x90,0x50,0xC3 };//跳到入口地址
 
char randsss[15] = { 0xE9,0x90,0xE8,0xE9,0xFF,0xEB,0x15,0x25 ,0x6A,0x07,0x27,0xFF,0x75,0x8E,0x5E };
struct BUFFERSTRUCT
{
    char value = 0;
    char match = 0;
};
vector<BUFFERSTRUCT>g_buffer;
void srandjunkcode()
{
    BUFFERSTRUCT buffer;
    buffer.value = jncode_one;
    g_buffer.push_back(buffer);   //1
 
    buffer.value = 0;
    g_buffer.push_back(buffer);         //2
 
    char x = jncode[rand() % 4];
    buffer.value = x;
    g_buffer.push_back(buffer);          //3
 
    if (x == 0xFF)
    {
        buffer.value = second[rand() % 2];
        g_buffer.push_back(buffer);     //4
    }
 
    int y = rand() % 3;
 
    for (int i = 0; i < y; i++)
    {
        buffer.value = randsss[rand() % 15];
        g_buffer.push_back(buffer);
    }
 
    for (int i = 0; i < 7; i++)
    {
        if (i == 0)
        {
            buffer.match = 1;
            buffer.value = jmpoep[i];
            g_buffer.push_back(buffer);
            continue;
        }
        /*if (i == 1)
        {
            buffer.match = 2;
            buffer.value = jmpoep[i];
            g_buffer.push_back(buffer);
            continue;
        }*/
        buffer.match = 0;
        buffer.value = jmpoep[i];
        g_buffer.push_back(buffer);
    }
 
    //修复数据
    vector< BUFFERSTRUCT>::iterator iter_buff = g_buffer.begin();
    for (int i = 0; i < g_buffer.size(); i++)
    {
        if ((*iter_buff).match == 1)
        {
            g_buffer.at(1).value = i - 2;
            break;
        }
 
        ++iter_buff;
    }
 
}





0x02 、反调试
三环的反调试手段比较有限,但是对于熟悉三环的人来说,玩出的花样会很多,对逆向能起到很大的阻击作用。
另外,如果把程序用驱动程序来保护,那么,不懂内核的人,过驱动有点困难。可以把驱动程序放到可执行程序里面,到一定时候再吐来执行。
下面是一些三环的的反调试手段:(都是一些老掉牙的东西,笑!)
[C++] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//检查程序是否被调试(发现被调试,程序直接卡死)
BOOL PreventDebug::Check_ZwSetInformationObject()
{
    /*-----------------------------------------------------------------------------------------------------------*/
    /*  在32位程序中,有人把钩子挂到64位的"ntdll.dll"上,然后来反反调试,可以用crc校验或者检测关键字节来反反反调试 */
    /*-----------------------------------------------------------------------------------------------------------*/
    HANDLE v3;
    HANDLE TargetHandle;
 
    typedef NTSTATUS(__stdcall* NTSETINFORMATIONOBJECT)(HANDLE objhandle, int objinforClass, PVOID objinfo, ULONG Length);
    NTSETINFORMATIONOBJECT pZwSetInformationObject;
 
    typedef BOOL (__stdcall* SETHANDLEINFORMATION)(_In_ HANDLE hObject, _In_ DWORD dwMask, _In_ DWORD dwFlags);
    SETHANDLEINFORMATION pSetHandleInformation;
 
    typedef BOOL (__stdcall* DUPLICATEHANDLE)(
            _In_ HANDLE hSourceProcessHandle,
            _In_ HANDLE hSourceHandle,
            _In_ HANDLE hTargetProcessHandle,
            _Outptr_ LPHANDLE lpTargetHandle,
            _In_ DWORD dwDesiredAccess,
            _In_ BOOL bInheritHandle,
            _In_ DWORD dwOptions
            );
    DUPLICATEHANDLE pDuplicateHandle;
 
    HMODULE hModule_1 = g_pfnLoadLibraryA("kernel32.dll");
    pSetHandleInformation = (SETHANDLEINFORMATION)g_pfnGetProcAddress(hModule_1, "SetHandleInformation");
    pDuplicateHandle = (DUPLICATEHANDLE)g_pfnGetProcAddress(hModule_1, "DuplicateHandle");
 
    HMODULE hModule = g_pfnLoadLibraryA("ntdll.dll");
    pZwSetInformationObject = (NTSETINFORMATIONOBJECT)g_pfnGetProcAddress(hModule, "ZwSetInformationObject");
 
    pDuplicateHandle((HANDLE)-1, (HANDLE)-1, (HANDLE)-1, &TargetHandle, 0, 0, 0);
    pZwSetInformationObject(TargetHandle, 4, &TargetHandle, 2);
    pSetHandleInformation(TargetHandle, 2, 2);
    pDuplicateHandle((HANDLE)-1, TargetHandle, (HANDLE)-1, &v3, 0, 0, 1);
#ifdef _WIN64
    return !v3 || v3 == (HANDLE)0xCCCCCCCCCCCCCCCC;
#endif // _WIN64
 
    return !v3 || v3 == (HANDLE)0xCCCCCCCC;
}
 
 
typedef struct tagPROCESSENTRY32or64
{
    DWORD   dwSize;
    DWORD   cntUsage;
    DWORD   th32ProcessID;          // this process
    ULONG_PTR th32DefaultHeapID;
    DWORD   th32ModuleID;           // associated exe
    DWORD   cntThreads;
    DWORD   th32ParentProcessID;    // this process's parent process
    LONG    pcPriClassBase;         // Base priority of process's threads
    DWORD   dwFlags;
#ifdef UNICODE
    WCHAR   szExeFile[MAX_PATH];    // Path
#else
    CHAR    szExeFile[MAX_PATH];    // Path
#endif // UNICODE
 
} PROCESSENTRY32or64, * LPPROCESSENTRY32or64;
#define TH32CS_SNAPPROCESS  0x00000002
 
 
//反虚拟机(寻找目标进程,成功返回true,失败返回false)
bool PreventDebug::GetProcessIdByName(TCHAR* szProcessName)
{
 
    typedef int(__stdcall* LSTRCMP_)(
#ifdef UNICODE
        _In_ LPCWSTR lpString1, _In_ LPCWSTR lpString2
#else
        _In_ LPCSTR lpString1, _In_ LPCSTR lpString2
#endif // UNICODE
        );
    LSTRCMP_ plstrcmpi;
 
    typedef HANDLE(__stdcall* CREATETOOLHELP32SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
    CREATETOOLHELP32SNAPSHOT pCreateToolhelp32Snapshot;
    typedef BOOL(__stdcall* PROCESS32FIRST)(HANDLE hSnapshot, LPPROCESSENTRY32or64 lppe);
    PROCESS32FIRST pProcess32First;
    typedef BOOL(__stdcall* PROCESS32NEXT)(HANDLE hSnapshot, LPPROCESSENTRY32or64 lppe);
    PROCESS32NEXT pProcess32Next;
 
    HMODULE hModule_1 = g_pfnLoadLibraryA("kernel32.dll");
    pCreateToolhelp32Snapshot = (CREATETOOLHELP32SNAPSHOT)g_pfnGetProcAddress(hModule_1, "CreateToolhelp32Snapshot");
 
#ifdef UINCODE
    plstrcmpi = (LSTRCMP_)g_pfnGetProcAddress(hModule_1, "lstrcmpiW");
    pProcess32First = (PROCESS32FIRST)g_pfnGetProcAddress(hModule_1, "Process32FirstW");
    pProcess32Next = (PROCESS32NEXT)g_pfnGetProcAddress(hModule_1, "Process32NextW");
 
#else
    plstrcmpi = (LSTRCMP_)g_pfnGetProcAddress(hModule_1, "lstrcmpiA");
    pProcess32First = (PROCESS32FIRST)g_pfnGetProcAddress(hModule_1, "Process32First");
    pProcess32Next = (PROCESS32NEXT)g_pfnGetProcAddress(hModule_1, "Process32Next");
#endif // UINCODE
 
    HANDLE hSnapProcess = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapProcess == NULL)
    {
        return FALSE;
    }
    PROCESSENTRY32or64 pe32 = { 0 };
    pe32.dwSize = sizeof(pe32);
    BOOL bRet = pProcess32First(hSnapProcess, &pe32);
    while (bRet)
    {
        if (plstrcmpi(pe32.szExeFile, szProcessName) == 0)
        {
            //g_pfnMessageBox(NULL, L"这是虚拟机", L"Hello PEDIY", MB_OK);
            return TRUE;
        }
        bRet = pProcess32Next(hSnapProcess, &pe32);
    }
    return FALSE;
}




0x03 、其他
1、在Stub.dll动态库,因为要作为程序的外壳程序,不能用到windows提供的API,想要用到这些API,
可以通过线程环境快(TEB)找到进程环境块(PEB)的kernel32.dll这个库的地址。之后获取GetProcessAddress()和LoadLibrary(),
那么,通过这两个函数和kernel32.dll的地址,就能获取其他API的地址了。
[Asm] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
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
//获取kernel32.dll的模块基址
UCHAR* PreventDebug::GetKernel32Addr()
{
    UCHAR* dwKernel32Addr;
#ifdef _WIN64
 
    _asm
    {//64位获取kernel32.dll的模块基址
        push rax
        mov rax, qword ptr gs : [60h] ;     // peb
        mov rax, [rax + 18h];               // LDR
        mov rax, [rax + 30h];               // InLoadOrderModuleList.Blink,
        mov rax, [rax];                     // [_LDR_MODULE.InLoadOrderModuleList].Blink kernelbase.dll
        mov rax, [rax];                     // [_LDR_MODULE.InLoadOrderModuleList].Blink kernel32.dll
        mov rax, [rax + 10h];               //[_LDR_MODULE.InLoadOrderModuleList]. BaseAddress
        mov dwKernel32Addr, rax
            pop rax
    }
#else
 
    __asm
    {//32位获取kernel32.dll的模块基址
        push eax
        mov eax, dword ptr fs : [0x30]   // eax = PEB的地址
        mov eax, [eax + 0x0C]            // eax = 指向PEB_LDR_DATA结构的指针
        mov eax, [eax + 0x1C]            // eax = 模块初始化链表的头指针InInitializationOrderModuleList
        mov eax, [eax]                   // eax = 列表中的第二个条目
        mov eax, [eax]                   // eax = 列表中的第三个条目
        mov eax, [eax + 0x08]            // eax = 获取到的Kernel32.dll基址(Win7下第三个条目是Kernel32.dll)
        mov dwKernel32Addr, eax
        pop eax
    }
#endif
 
    return dwKernel32Addr;
}



2、如果在外壳程序中,有复杂的操作,要用到容器,比如矢量、链表或者树,不能用Windows提供的标准模板库,因为这里面说不一定就会用到API,从而导致程序出错。
可以仿照标准模板库设计自己的库,比如设计一个vector容器:
[C++] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#pragma once
#include <Windows.h>
 
#define SUCCESS         1   //成功
#define INDEX_ERROR         -1  //失败
#define MALLOC_ERROR    -2  //申请内存失败
#define INDEX_ERROR     -3  //错误的索引号
 
using namespace std;
 
//在头文件中:
template <class T_ELE>
class vector_
{
public:
    vector_();
    vector_(DWORD dwSize);
    ~vector_();
public:
    DWORD at(DWORD dwIndex, OUT T_ELE* pEle);   //根据给定的索引得到元素
    DWORD push_back(T_ELE Element);             //将元素储存到容器最后一个位置
    VOID pop_back();                            //删除最后一个元素
    DWORD insert(DWORD dwIndex, T_ELE Element); //向指定位置新增一个元素
    DWORD capacity();                           //返回在不增容的情况下,还能储存多少元素
    VOID clear();                               //清空所有元素
    BOOL empty();                               //判断vector_是否为空 返回true时为空
    VOID erase(DWORD dwIndex);                  //删除指定元素
    DWORD size();                               //返回vector_元素数量的大小
    void outoforder(vector_< T_ELE>&arr);     //乱序排序(参数arr,既是输入参数,也是输出参数)
 
    void v_memcpy(void* _Dst, const void* _Res, DWORD _Size);//内存拷贝(深拷贝)
public:
 
private:
    BOOL expand();
private:
    DWORD m_dwIndex;    //下一个可用索引
    DWORD m_dwIncrement;//每次增容的大小
    DWORD m_dwLen;      //当前容器的长度
    DWORD m_dwInitSize; //默认初始化大小
    T_ELE* m_pVector;   //容器指针
 
public:
 
//迭代器
    class iterator
    {
    public:
        iterator(T_ELE* p = nullptr) :_ptr(p) {}
        bool operator!=(const iterator& it)const
        {
            return _ptr != it._ptr;
        }
        void operator++()
        {
            ++_ptr;
        }
        T_ELE* operator+(int index)
        {
            return _ptr + index;
        }
        T_ELE* operator-(int index)
        {
            return _ptr - index;
        }
        T_ELE& operator*()
        {
            return *_ptr;
        }
        const T_ELE& operator*()const
        {
            return *_ptr;
        }
    private:
        T_ELE* _ptr;
    };
    iterator begin()
    {
        return iterator(_first);
    }
    iterator end()
    {
        return iterator(_end);
    }
 
    T_ELE* _first;//指向数组起始位置
    T_ELE* _end;//指向数组空间的后继位置
};
 
template<class T_ELE>
inline vector_<T_ELE>::vector_() :m_dwInitSize(100), m_dwIncrement(5)
{
    m_pVector = new T_ELE[100];
    memset(m_pVector, 0, m_dwInitSize * sizeof(T_ELE));
    m_dwLen = m_dwInitSize;
    m_dwIndex = 0;
    _first = m_pVector;
}
 
template<class T_ELE>
inline vector_<T_ELE>::vector_(DWORD dwSize) :m_dwIncrement(5)
{
    m_pVector = new T_ELE[dwSize];
    memset(m_pVector, 0, dwSize);
    m_dwLen = dwSize;
    m_dwIndex = 0;
}
 
template<class T_ELE>
inline vector_<T_ELE>::~vector_()
{
    delete[] m_pVector;
    m_pVector = NULL;
}
 
//根据给定的索引得到元素
template<class T_ELE>
inline DWORD vector_<T_ELE>::at(DWORD dwIndex, OUT T_ELE* pEle)
{
    if (!(dwIndex >= 0 && dwIndex < m_dwLen))
    {
        //cout << "索引超出范围" << endl;
        return INDEX_ERROR;
    }
    *pEle = m_pVector[dwIndex];
    return 0;
}
 
//将元素储存到容器最后一个位置
template<class T_ELE>
inline DWORD vector_<T_ELE>::push_back(T_ELE Element)
{
    //判断申请内存是否够用
    if (m_dwIndex >= 100)
        expand();
 
    m_pVector[m_dwIndex] = Element;
    _end = m_pVector + m_dwIndex;
    m_dwIndex++;
    return 0;
}
 
//删除最后一个元素
template<class T_ELE>
inline VOID vector_<T_ELE>::pop_back()
{
    m_pVector[m_dwIndex - 1] = 0;
    --m_dwIndex;
    return VOID();
}
 
//向指定位置新增一个元素
template<class T_ELE>
inline DWORD vector_<T_ELE>::insert(DWORD dwIndex, T_ELE Element)
{
    //判断申请内存是否够用
    if (m_dwIndex >= 100)
        expand();
 
    //无符号转换为有符号
    if ((int)dwIndex < 0)
        dwIndex = 0;
 
    for (int i = 0; i < m_dwIndex - dwIndex + 1; i++)
    {
        m_pVector[m_dwIndex + 1 - i] = m_pVector[m_dwIndex - i];
    }
    m_pVector[dwIndex] = Element;
    m_dwIndex++;
    return 0;
}
 
//返回在不增容的情况下,还能储存多少元素
template<class T_ELE>
inline DWORD vector_<T_ELE>::capacity()
{
    return m_dwLen - m_dwIndex;
}
 
//清空所有元素
template<class T_ELE>
inline VOID vector_<T_ELE>::clear()
{
    for (int i = 0; i < m_dwIndex + 1; i++)
        m_pVector[i] = NULL;
    m_dwIndex = 0;
    return VOID();
}
 
//判断vector_是否为空 返回true时为空
template<class T_ELE>
inline BOOL vector_<T_ELE>::empty()
{
    for (int i = 0; i < m_dwLen; i++)
    {
        if (m_pVector[i] != NULL)
            return false;
    }
    return true;
}
 
//删除指定元素
template<class T_ELE>
inline VOID vector_<T_ELE>::erase(DWORD dwIndex)
{
    --dwIndex;//删除第dwIndex个元素,那么下标应该减减
    for (int i = 0; i < m_dwIndex - dwIndex + 1; i++)
    {
        m_pVector[dwIndex + i] = m_pVector[dwIndex + i + 1];
    }
    --m_dwIndex;
    return VOID();
}
 
//返回vector_元素数量的大小
template<class T_ELE>
inline DWORD vector_<T_ELE>::size()
{
    return m_dwIndex;
}
 
//乱序排序(参数arr,既是输入参数,也是输出参数)
template<class T_ELE>
inline void vector_<T_ELE>::outoforder(vector_<T_ELE>& arr)
{
 
    vector_<T_ELE>::iterator ter_1 = arr.begin();
    vector_<T_ELE>temp_arr;
    int calc = 0;
    int length = arr.size();
    for (int i = 0; i < length; i++)
    {
        DWORD lls = GetTickCount() % (length - calc);
 
        temp_arr.push_back(*(ter_1 + lls));
 
        arr.erase(lls + 1);
 
        ++calc;
    }
 
    vector_<T_ELE>::iterator ter_2 = temp_arr.begin();
    for (int i = 0; i < length; i++)
    {
        *(ter_1 + i) = *(ter_2 + i);
    }
}
 
template<class T_ELE>
inline void vector_<T_ELE>::v_memcpy(void* _Dst, const void* _Res, DWORD _Size)
{
    for (int i = 0; i < _Size; i++)
    {
        ((char*)_Dst)[i] = ((char*)_Res)[i];
    }
}
 
 
 
template<class T_ELE>
inline BOOL vector_<T_ELE>::expand()
{
    int nLength = (int)m_dwIncrement + (int)m_dwLen;
    //重新申请一块内存,大小为nLength
    T_ELE* pNewBuff = new T_ELE[nLength];
    memset(pNewBuff, 0, nLength * sizeof(T_ELE));
    //把原始数据拷贝到新内存
    memcpy_s(pNewBuff, nLength * sizeof(T_ELE), m_pVector, m_dwLen * sizeof(T_ELE));
 
    //释放原来的空间
    delete[] m_pVector;
 
    //把新指针赋值给m_pVector
    m_pVector = pNewBuff;
 
    _first = m_pVector;
 
    //为各种属性赋值
    m_dwLen = nLength;
 
    return SUCCESS;
}

注意,这个vector_里的new  delete  GetTickCount()几个API必须全部替换掉,new可以HeapAlloc来替换掉,delete用HeapFree来替换,
,HeapAlloc、HeapFree、GetTickCount都可以通过kernel32.dll找到其地址。


3、在外壳里面怎么获取随机数的问题,可以直接逆向srand()和rand()两个函数,
以下的随机数函数就是照搬srand()和rand():
[C++] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//随机数种子
DWORD holdrand = 0;
 
void srand_v(DWORD num)//随机因子,可以取日期
{
    holdrand = num;
}
 
 
DWORD rand_v()
{
    DWORD res = 0;
    _asm {
        mov eax, holdrand
        imul eax, eax, 343fdh
        add eax, 269ec3h
        mov holdrand, eax
        mov eax, holdrand
        sar eax, 10h
        and eax, 7fffh
        mov res, eax
    }
 
    return res;
}


完!

免费评分

参与人数 7威望 +1 吾爱币 +28 热心值 +7 收起 理由
luxuryang + 1 + 1 我很赞同!
zbby + 1 + 1 用心讨论,共获提升!
antiol + 3 + 1 我很赞同!
nj001 + 1 + 1 热心回复!
花好s月圆 + 1 + 1 我看不懂就很厉害。
xouou + 1 + 1 不明觉厉
苏紫方璇 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

hszt 发表于 2020-10-2 09:44
作为一个伸手党,弱弱的问一句,有成品吗
花好s月圆 发表于 2020-9-30 21:22
antiol 发表于 2020-9-30 22:31
 楼主| 舒默哦 发表于 2020-10-1 09:54
antiol 发表于 2020-9-30 22:31
见证开源强壳即将诞生

离强壳差远了,我懂得并不多,能写出感觉都脱了一层皮
zbby 发表于 2020-10-31 03:25
antiol 发表于 2020-9-30 22:31
见证开源强壳即将诞生

貌似已经有好几个了(开源强壳)
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-16 10:29

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表