吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

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

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

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



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




0x00、IAT加密
第一步
首先把IAT表转存到一个临时数据结构中,然后清除IAT和INT表,最后把临时数据结构中的函数名称加密,等待下一步处理。
[C++] 纯文本查看 复制代码
//保存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++] 纯文本查看 复制代码
//清除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++] 纯文本查看 复制代码
//处理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++] 纯文本查看 复制代码
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++] 纯文本查看 复制代码
//检查程序是否被调试(发现被调试,程序直接卡死)
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] 纯文本查看 复制代码
//获取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++] 纯文本查看 复制代码
#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++] 纯文本查看 复制代码
//随机数种子
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, 2024-5-24 05:56

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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