舒默哦 发表于 2020-9-30 18:35

【VC】【笔记】自写vmp壳子编写报告(二)


https://static.52pojie.cn/static/image/hrline/1.gif

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

https://static.52pojie.cn/static/image/hrline/1.gif


0x00、IAT加密
第一步
首先把IAT表转存到一个临时数据结构中,然后清除IAT和INT表,最后把临时数据结构中的函数名称加密,等待下一步处理。

//保存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.m_dwIATAddr = (ULONG_PTR)pIAT - (ULONG_PTR)m_pFileBuf;
                                m_pMyImport.m_bIsOrdinal = TRUE;
#ifdef _WIN64
                                m_pMyImport.m_Ordinal = pIAT->u1.Ordinal & 0x7FFFFFFFFFFFFFFF;
#else
                                m_pMyImport.m_Ordinal = pIAT->u1.Ordinal & 0x7FFFFFFF;
#endif // DEBUG

                                m_pMyImport.m_dwModNameRVA = TempModRVA;
                        }
                        else
                        {
                                //保存名称号出方式的函数信息
                                m_pMyImport.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.m_dwFunNameRVA = TempFunRVA;
                                m_pMyImport.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;
                m_pMyImport;
                memcpy_s(&stcTemp, sizeof(MYIMPORT), &m_pMyImport, sizeof(MYIMPORT));
                memcpy_s(&m_pMyImport, sizeof(MYIMPORT), &m_pMyImport, sizeof(MYIMPORT));
                memcpy_s(&m_pMyImport, sizeof(MYIMPORT), &stcTemp, sizeof(MYIMPORT));
        }

        //保存信息
        m_dwSizeOfModBuf = dwSizeOfModBuf;
        m_dwSizeOfFunBuf = dwSizeOfFunBuf;
}

//清除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的表,放到虚拟机中解密,最后跳到花指令处,每次启动程序,
花指令都是不一样的(就像每次启动程序进入虚拟机,地址都是打乱的一样),然后解密,最终跳到要去的地方。

//处理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"; //跳到花指处
}

https://static.52pojie.cn/static/image/hrline/1.gif

0x01、随机花指令构造器
构造花指令,可以使用无条件跳转,比如ret、call、jmp来跳转,也可以使用有条件跳转,跳转的越多,能给人造成的困扰越大。
下面的是一个随机花指令构造器,很简单,只有一跳,每调用一次srandjunkcode()就会构造出一条花指令。
当然,可以构造出一个多跳、往回跳、来回往复的花指令机器,并把关键数据插入其中。

char jncode_one= 0xEB;
char jncode = { 0xE8,0xE9,0xFF,0xEB };

char second = { 0x15,0x25 };
char jmpoep = { 0xb8,0x90,0x90,0x90,0x90,0x50,0xC3 };//跳到入口地址

char randsss = { 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;
    buffer.value = x;
    g_buffer.push_back(buffer);          //3

    if (x == 0xFF)
    {
      buffer.value = second;
      g_buffer.push_back(buffer);   //4
    }

    int y = rand() % 3;

    for (int i = 0; i < y; i++)
    {
      buffer.value = randsss;
      g_buffer.push_back(buffer);
    }

    for (int i = 0; i < 7; i++)
    {
      if (i == 0)
      {
            buffer.match = 1;
            buffer.value = jmpoep;
            g_buffer.push_back(buffer);
            continue;
      }
      /*if (i == 1)
      {
            buffer.match = 2;
            buffer.value = jmpoep;
            g_buffer.push_back(buffer);
            continue;
      }*/
      buffer.match = 0;
      buffer.value = jmpoep;
      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;
    }

}

https://static.52pojie.cn/static/image/hrline/1.gif


0x02 、反调试
三环的反调试手段比较有限,但是对于熟悉三环的人来说,玩出的花样会很多,对逆向能起到很大的阻击作用。
另外,如果把程序用驱动程序来保护,那么,不懂内核的人,过驱动有点困难。可以把驱动程序放到可执行程序里面,到一定时候再吐来执行。
下面是一些三环的的反调试手段:(都是一些老掉牙的东西,笑!)

//检查程序是否被调试(发现被调试,程序直接卡死)
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;    // Path
#else
        CHAR    szExeFile;    // Path
#endif // UNICODE

} PROCESSENTRY32or64, * LPPROCESSENTRY32or64;
#define TH32CS_SNAPPROCESS0x00000002


//反虚拟机(寻找目标进程,成功返回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;
}


https://static.52pojie.cn/static/image/hrline/1.gif


0x03 、其他
1、在Stub.dll动态库,因为要作为程序的外壳程序,不能用到windows提供的API,想要用到这些API,
可以通过线程环境快(TEB)找到进程环境块(PEB)的kernel32.dll这个库的地址。之后获取GetProcessAddress()和LoadLibrary(),
那么,通过这两个函数和kernel32.dll的地址,就能获取其他API的地址了。

//获取kernel32.dll的模块基址
UCHAR* PreventDebug::GetKernel32Addr()
{
        UCHAR* dwKernel32Addr;
#ifdef _WIN64

        _asm
        {//64位获取kernel32.dll的模块基址
                push rax
                mov rax, qword ptr gs : ;                // peb
                mov rax, ;                                // LDR
                mov rax, ;                                // InLoadOrderModuleList.Blink,
                mov rax, ;                                                // .Blink kernelbase.dll
                mov rax, ;                                                // .Blink kernel32.dll
                mov rax, ;                                //. BaseAddress
                mov dwKernel32Addr, rax
                        pop rax
        }
#else

        __asm
        {//32位获取kernel32.dll的模块基址
                push eax
                mov eax, dword ptr fs :    // eax = PEB的地址
                mov eax,             // eax = 指向PEB_LDR_DATA结构的指针
                mov eax,             // eax = 模块初始化链表的头指针InInitializationOrderModuleList
                mov eax,                    // eax = 列表中的第二个条目
                mov eax,                    // eax = 列表中的第三个条目
                mov eax,             // eax = 获取到的Kernel32.dll基址(Win7下第三个条目是Kernel32.dll)
                mov dwKernel32Addr, eax
                pop eax
        }
#endif

        return dwKernel32Addr;
}


2、如果在外壳程序中,有复杂的操作,要用到容器,比如矢量、链表或者树,不能用Windows提供的标准模板库,因为这里面说不一定就会用到API,从而导致程序出错。
可以仿照标准模板库设计自己的库,比如设计一个vector容器:

#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;
        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;
        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;
        return 0;
}

//将元素储存到容器最后一个位置
template<class T_ELE>
inline DWORD vector_<T_ELE>::push_back(T_ELE Element)
{
        //判断申请内存是否够用
        if (m_dwIndex >= 100)
                expand();

        m_pVector = Element;
        _end = m_pVector + m_dwIndex;
        m_dwIndex++;
        return 0;
}

//删除最后一个元素
template<class T_ELE>
inline VOID vector_<T_ELE>::pop_back()
{
        m_pVector = 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_pVector;
        }
        m_pVector = 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 = 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 != 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 = m_pVector;
        }
        --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) = ((char*)_Res);
        }
}



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;
        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_里的newdeleteGetTickCount()几个API必须全部替换掉,new可以HeapAlloc来替换掉,delete用HeapFree来替换,
,HeapAlloc、HeapFree、GetTickCount都可以通过kernel32.dll找到其地址。


3、在外壳里面怎么获取随机数的问题,可以直接逆向srand()和rand()两个函数,
以下的随机数函数就是照搬srand()和rand():

//随机数种子
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;
}
https://static.52pojie.cn/static/image/hrline/4.gif
完!

hszt 发表于 2020-10-2 09:44

{:1_918:}作为一个伸手党,弱弱的问一句,有成品吗

花好s月圆 发表于 2020-9-30 21:22

太优秀了,厉害。

antiol 发表于 2020-9-30 22:31

见证开源强壳即将诞生

舒默哦 发表于 2020-10-1 09:54

antiol 发表于 2020-9-30 22:31
见证开源强壳即将诞生

{:301_1008:}离强壳差远了,我懂得并不多,能写出感觉都脱了一层皮

zbby 发表于 2020-10-31 03:25

antiol 发表于 2020-9-30 22:31
见证开源强壳即将诞生

貌似已经有好几个了(开源强壳)
页: [1]
查看完整版本: 【VC】【笔记】自写vmp壳子编写报告(二)