【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
完!
{:1_918:}作为一个伸手党,弱弱的问一句,有成品吗 太优秀了,厉害。 见证开源强壳即将诞生 antiol 发表于 2020-9-30 22:31
见证开源强壳即将诞生
{:301_1008:}离强壳差远了,我懂得并不多,能写出感觉都脱了一层皮 antiol 发表于 2020-9-30 22:31
见证开源强壳即将诞生
貌似已经有好几个了(开源强壳)
页:
[1]