sality感染文件恢复算法

实习期的一个任务, 写sality专杀.
首先逆向了ag的母体, 因为之前没接触该病毒, 就把ag详细看了遍, 之后开始看其他的变种.
其中ag,bh较复杂, bh是ag的一种特殊情况, 即那两个key均为0的情况.
相关代码:
这代码中的startVM为一个指令模拟虚拟机, 用于模拟指令执行并得到病毒跳转出口值(push reg/ret, jmp reg这两种情况), 这虚拟机代码是公司的所以就不公开了.
附件链接为我的分析笔记和样本
链接:https://pan.baidu.com/s/1k90i--W00qoBf1aW2lmNbQ
提取码:vyjc
密码: infected

int MatchSalityAG(BYTE* data, DWORD size)
{
	if (size == 0)
	{
		return FALSE;
	}
	unsigned int i = 0;
	unsigned char * pTemp = (unsigned char*)data;         //这里没必要备份, 因为修改pData并不会影响到原来的指针..

	for (; i < size - 0x20; i++)//9字节
	{
		if (*(DWORD*)(pTemp) == 0xC1 && *(WORD*)(pTemp + 4) == 0x0573)     //C1 00 00 00 73 05 E9 XX XX FF FF  
		{
			if (*(pTemp + 6) == 0xE9)
			{
				pTemp += 11;
				goto SearchContinue;
			}
		}
		pTemp++;
	}
	return FALSE;//没搜到第一个特征直接返回
SearchContinue://继续搜下一个特征9字节
	for (; i < size - 0x10; i++)
	{
		if (*(DWORD*)pTemp == 0xFEE2 || *(DWORD*)pTemp == 0xEEE2)    // e2 fe(ee) 00 00 0f 8c xx xx ff ff c3
		{
			pTemp += 4;
			if (*(WORD*)pTemp == 0x8C0F&& *(pTemp + 6) == 0xC3)
				return (int)pTemp;
		}
		pTemp++;
	}
	return FALSE;
}

int MatchSalityAC(BYTE* data)
{
	PIMAGE_DOS_HEADER pidh;
	PIMAGE_NT_HEADERS pinh;
	PIMAGE_SECTION_HEADER pish;
	pidh = (PIMAGE_DOS_HEADER)data;
	pinh = (PIMAGE_NT_HEADERS)(data + pidh->e_lfanew);
	pish = (PIMAGE_SECTION_HEADER)(pinh + 1);

	DWORD oep_rva = pinh->OptionalHeader.AddressOfEntryPoint;
	DWORD oep_fo = RVA2FO(pish, pinh->FileHeader.NumberOfSections, oep_rva);

	BYTE* data_oep = data + oep_fo;

	if (data[oep_fo] == 0x60 && data[oep_fo + 1] == 0xe8)
	{
		DWORD place_rva = oep_rva + 6 + *(DWORD*)&data_oep[2];  //开门那个call到的地方的位置
		DWORD place_fo = RVA2FO(pish, pinh->FileHeader.NumberOfSections, place_rva);

		unsigned char sig[] =
		{
			0x33, 0xC9, 0x81, 0xC1, 0xE8, 0x03, 0x00, 0x00, 0x8B, 0x2C,
			0x24, 0x90, 0x81, 0xC1, 0x18, 0x24, 0x00, 0x00
		};

		if (!memcmp(data + place_fo, sig, sizeof(sig)))
		{
			return 1;
		}
	}

	return 0;

}

int MatchSalityBG(BYTE* data)
{
	PIMAGE_DOS_HEADER pidh;
	PIMAGE_NT_HEADERS pinh;
	PIMAGE_SECTION_HEADER pish;
	pidh = (PIMAGE_DOS_HEADER)data;
	pinh = (PIMAGE_NT_HEADERS)(data + pidh->e_lfanew);
	pish = (PIMAGE_SECTION_HEADER)(pinh + 1);

	DWORD oep_rva = pinh->OptionalHeader.AddressOfEntryPoint;
	DWORD oep_fo = RVA2FO(pish, pinh->FileHeader.NumberOfSections, oep_rva);

	BYTE* data_oep = data + oep_fo;

	if (data[oep_fo] == 0x60 && data[oep_fo + 1] == 0xe8)
	{
		DWORD place_rva = oep_rva + 6 + *(DWORD*)&data_oep[2];  //开门那个call到的地方的位置
		DWORD place_fo = RVA2FO(pish, pinh->FileHeader.NumberOfSections, place_rva);

		unsigned char sig[] =
		{
			0x33, 0xC9, 0x8b, 0x2c, 0x24, 0x81, 0xed, 0x06, 0x10, 0x40, 0x00, 0xc3
		};

		if (!memcmp(data + place_fo, sig, sizeof(sig)))
		{
			return 1;
		}
	}

	return 0;

}

int MatchSalityAB(BYTE* data, DWORD oep_fo)
{
	//根据pusha
	//call $+5来初步判断...
	if (*(data + oep_fo) == 0x60 && *(data + oep_fo + 1) == 0xe8 && *(DWORD*)(data + oep_fo + 2) == 0)
	{
		return 1;
	}
	return 0;
}

int MatchSalityAA(BYTE* data, DWORD oep_fo)
{
	//根据pusha
	//然后第二个不是call $+5... 之后得做更进一步的判断
	if (*(data + oep_fo) == 0x60 && *(data + oep_fo + 1) != 0xe8)
	{
		return 1;
	}
	return 0;
}

//从最后一个区段搜索标志: 病毒区段开始的四个字节为最后一个区段名字转换成大写字母. 
int MatchSalityAE(BYTE* data)
{
	PIMAGE_DOS_HEADER pidh;
	PIMAGE_NT_HEADERS pinh;
	PIMAGE_SECTION_HEADER pish;
	pidh = (PIMAGE_DOS_HEADER)data;
	pinh = (PIMAGE_NT_HEADERS)(data + pidh->e_lfanew);
	pish = (PIMAGE_SECTION_HEADER)(pinh + 1);

	DWORD oep_rva = pinh->OptionalHeader.AddressOfEntryPoint;
	DWORD oep_fo = RVA2FO(pish, pinh->FileHeader.NumberOfSections, oep_rva);

	PIMAGE_SECTION_HEADER pish_last = pish + pinh->FileHeader.NumberOfSections - 1;

	BYTE signame[5] = { 0 };
	memcpy(signame, pish_last->Name, 5);

	//转小写
	for (int i = 0; i < 5; ++i)
	{
		if (signame[i] >= 0x61 && signame[i] <= 0x7a)
		{
			signame[i] -= 0x20;
		}
	}

	if (pish_last->SizeOfRawData == 0)
	{
		return 0;
	}

	for (int i = 0; i < (int)pish_last->SizeOfRawData - 0x10; ++i)
	{
		if (memcmp(data + pish_last->PointerToRawData + i, signame, 4))
		{
			continue;
		}
		if (((pish_last->PointerToRawData + i) & 0xff) != 0) //稍微过滤一下,因为病毒区段会对齐一下. 避免某些情况下的误报..
		{
			return 0;
		}
		return pish_last->PointerToRawData + i; //找到了..
	}
	return 0;
	
}
//扫描文件,恢复被感染文件
//arg1: 文件全路径
//arg2: 非0代表不恢复, 0代表恢复
//返回值:
//-1: 打开文件出错/文件大小问题/文件映射出错
//0: 未发现
//1: vm模拟出错,无法判断
//2: 文件的PE头有问题
//3: 是sality.af, 未尝试修复
//4: 是sality.af, 修复成功
//5: 是sality.af, 修复失败
//6: 是sality.ag/bh, 未尝试修复    因为ag,bh非常类似, 所以就不单独分出来了..
//7: 是sality.ag/bh, 修复成功
//8: 是sality.ag/bh, 修复失败
//9: 是sality.ac, 未尝试修复
//10:是sality.ac, 修复成功
//11:是sality.ac, 修复失败
//12:是sality.ab, 未尝试修复
//13:是sality.ab, 修复成功
//14:是sality.ab, 修复失败
//15:是sality.aa, 未尝试修复
//16:是sality.aa, 修复成功
//17:是sality.aa, 修复失败
//18:是sality.bg, 未尝试修复
//19:是sality.bg, 修复成功
//20:是sality.bg, 修复失败
//21:是sality.ae, 未尝试修复
//22:是sality.ae, 修复成功
//23:是sality.ae, 修复失败
//24:是sality.gen, 没什么操作.

//ab和ag貌似会互相误报, 所以我把ab放到ag前面去了..

int ScanFile(_In_ CHAR* szFileName, _In_ int bScanOnly)
{
	int result = 0;
	HANDLE hFileMapping;
	BYTE* data;
	DWORD dwFileSize;
	DWORD oep_fo;
	PIMAGE_DOS_HEADER pidh = NULL;
	PIMAGE_NT_HEADERS pinh = NULL;
	PIMAGE_SECTION_HEADER pish = NULL;
	HANDLE hFile;
	BOOL bFreeFlag = FALSE;
	int fileoriginalsize = 0;
	

	//参数检查
	if (szFileName == NULL || !strcmp(szFileName, ""))
	{
		result = -1;
		goto end1;
	}

	if (bScanOnly)
	{
		hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	}
	else
	{
		hFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	}

	if (hFile == INVALID_HANDLE_VALUE)
	{
		result = -1;
		goto end1;
	}

	DWORD dwSizeHigh = 0;
	dwFileSize = GetFileSize(hFile, &dwSizeHigh);

	if (dwFileSize < 0x1000 || dwSizeHigh)
	{
		result = -1;
		goto end2;
	}
	//sality.gen   这个gen就是generator,也就是母体..包括下面那些变种的所有母体..
	//采用MD5比较
	if (MatchSalityGen(szFileName))
	{
		result = 24;
		goto end2;
	}

	if (bScanOnly)
	{
		hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, NULL, NULL, NULL);
	}
	else
	{
		hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, NULL, NULL, NULL);
	}


	if (hFileMapping == NULL)
	{
		if (bScanOnly == FALSE)
		{
			goto end3;
		}
		DWORD dwTemp = 0;
		data = (BYTE*)malloc(dwFileSize);
		ReadFile(hFile, data, dwFileSize, &dwTemp, NULL);
		bFreeFlag = TRUE;
		if (dwTemp != dwFileSize)
		{
			result = -1;
			goto end3;
		}

		goto new1;
	}
	
	

	if (bScanOnly)
	{
		data = (BYTE*)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
	}
	else
	{
		data = (BYTE*)MapViewOfFile(hFileMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
	}


	if (data == 0)
	{
		result = -1;
		goto end3;
	}
new1:
	pidh = (PIMAGE_DOS_HEADER)data;

	if (pidh->e_magic != IMAGE_DOS_SIGNATURE)
	{
		result = 2;
		goto end4;
	}

	if ((DWORD)pidh->e_lfanew > 0x1000)
	{
		result = 2;
		goto end4;
	}

	pinh = (PIMAGE_NT_HEADERS)(data + pidh->e_lfanew);

	pish = (PIMAGE_SECTION_HEADER)(pinh + 1);
	
	if (pinh->Signature != IMAGE_NT_SIGNATURE)
	{
		result = 2;
		goto end4;
	}


	if ((pish[pinh->FileHeader.NumberOfSections - 1].PointerToRawData > dwFileSize)|| (pinh->OptionalHeader.Magic & 0x200))
	{
		result = 2;
		goto end4;
	}

	if (pinh->OptionalHeader.AddressOfEntryPoint < pinh->OptionalHeader.BaseOfCode)
	{
		result = 2;
		goto end4;
	}

	oep_fo = RVA2FO(pish, pinh->FileHeader.NumberOfSections, pinh->OptionalHeader.AddressOfEntryPoint);


	//sality.aa
	if (MatchSalityAA(data, oep_fo))
	{
		int r32 = startVM((int)data, pinh->OptionalHeader.AddressOfEntryPoint, pinh->OptionalHeader.ImageBase, pinh->OptionalHeader.SizeOfImage);
		if (r32 == 0)
		{
			result = 1;    //这里不直接goto end4, 让他去匹配后面的
		}
		else
		{
			BYTE key[0x16] = { 0 };
			memcpy(key, data + r32 + 0x1000, 0x16);

			for (int k = 1; k < 0x16; ++k)
			{
				BYTE arr[0x100] = { 0 };
				for (int i = 0; i < 0x100; ++i)
				{
					arr[i] = i;
				}
				BYTE ah = 0, al = 0, dl = 0;
				for (int i = 0; i < 0x100; ++i)
				{
					al = arr[i];
					dl += key[i % k];
					dl += al;
					ah = arr[dl];
					arr[dl] = al;
					arr[i] = ah;
				}

				BYTE bl = 0, ch = 0;
				dl = 0;
				BYTE datatodecrypt[0x2000] = { 0 };
				memcpy(datatodecrypt, data + r32 + 0x1116, 0x2000);
				for (int i = 0; i < 0x2000; ++i)  //就解密这些就够了
				{
					dl += 1;
					bl += arr[dl];
					al = arr[dl];
					ch = arr[bl];
					arr[bl] = al;
					arr[dl] = ch;
					al += ch;
					al = arr[al];
					datatodecrypt[i] ^= al;
				}
				BYTE sig1[] = { 0xe8,0x00,0x00,0x00,0x00 };
				if (memcmp(datatodecrypt, sig1, sizeof(sig1)))
				{
					if (k == 0x15) //说明所有的都已经尝试过了
					{
						result = 0;
						goto next1;
					}
					continue;
				}

				if (bScanOnly)
				{
					result = 15;  //到这儿就可以确定是aa了..
					goto end4;
				}

				//
				DWORD dwDataSize = *(DWORD*)(datatodecrypt + 0x288a - 0x1116) ^ *(DWORD*)(datatodecrypt + 0x17f6 - 0x1116);
				if (dwDataSize > 0x2000 - (0x288e - 0x1116))
				{
					result = 17;  //说明我前面弄的datatodecrypt小了.. 不过应该不会出现这种情况, 我目测这个字节会小于0x200
					goto end4;
				}
				memcpy(data + oep_fo, datatodecrypt + 0x288e - 0x1116, dwDataSize);

				if (*(DWORD*)&datatodecrypt[0x24a1 - 0x1116] == *(DWORD*)&datatodecrypt[0x24a5 - 0x1116])
				{
					fileoriginalsize = *(DWORD*)&datatodecrypt[0x24a1 - 0x1116];
				}

				result = 16;
				goto end4;


			}
		}


	}
next1:

	//sality.ab
	if (MatchSalityAB(data, oep_fo))
	{
		int r32 = startVM((int)data, pinh->OptionalHeader.AddressOfEntryPoint, pinh->OptionalHeader.ImageBase, pinh->OptionalHeader.SizeOfImage);

		if (r32 == 0)
		{
			result = 1;
			goto end4;
		}
		else
		{
			BYTE key[0x16] = { 0 };
			memcpy(key, data + r32 + 0x1000, 0x16);

			for (int k = 1; k < 0x16; ++k)
			{
				BYTE arr[0x100] = { 0 };
				for (int i = 0; i < 0x100; ++i)
				{
					arr[i] = i;
				}
				BYTE ah = 0, al = 0, dl = 0;
				for (int i = 0; i < 0x100; ++i)
				{
					al = arr[i];
					dl += key[i % k];
					dl += al;
					ah = arr[dl];
					arr[dl] = al;
					arr[i] = ah;
				}

				BYTE bl = 0, ch = 0;
				dl = 0;
				BYTE datatodecrypt[0x2000] = { 0 };
				memcpy(datatodecrypt, data + r32 + 0x1116, 0x2000);
				for (int i = 0; i < 0xef; ++i)
				{
					bl += arr[1 + dl];
					al = arr[1 + dl];
					ch = arr[bl];
					arr[bl] = al;
					arr[1 + dl] = ch;
					al += ch;
					al = arr[al];
					dl += 1;
					datatodecrypt[i] ^= al;
				}
				BYTE sig1[] = { 0xba,0xc2,0xce,0x00,0x00,0x8b,0xdd,0x33,0xc9 };
				if (memcmp(datatodecrypt, sig1, sizeof(sig1)))
				{
					if (k == 0x15) //说明所有的都已经尝试过了
					{
						result = 0;
						goto next2;
					}
					continue;
				}

				if (bScanOnly) //到这里,可以确定是ab了.
				{
					result = 12;
					goto end4;
				}

				for (int i = 0; i < 0x2000 - (0x3e - 0x16); i += 2)
				{
					*(WORD*)&datatodecrypt[0x3e - 0x16 + i] ^= *(WORD*)&datatodecrypt[0xc] * i - i / 2;
				}

				BYTE sig2[] = { 0x8d,0xb5,0x16,0x19,0x00,0x00 };
				if (memcmp(datatodecrypt + 0x41 - 0x16, sig2, sizeof(sig2)))
				{
					result = 14;
					goto end4;
				}

				DWORD dwSize = *(DWORD*)&datatodecrypt[0x32];
				memcpy(data + oep_fo, &datatodecrypt[0x1916 - 0x1116], dwSize);

				if (*(DWORD*)&datatodecrypt[0x24a1-0x1116] == *(DWORD*)&datatodecrypt[0x24a5-0x1116])
				{
					fileoriginalsize = *(DWORD*)&datatodecrypt[0x24a1-0x1116];
				}


				result = 13;
				goto end4;
			}



		}// end of for k

	}
next2:

	//sality.ac
	if (MatchSalityAC(data))
	{
		if (bScanOnly)
		{
			result = 0x9;
			goto end4;
		}

		DWORD oep_rva = pinh->OptionalHeader.AddressOfEntryPoint;
		BYTE* data_oep = data + oep_fo;

		DWORD datatodecrypt_rva = oep_rva + *(DWORD*)&data_oep[7];
		DWORD temp_fo = RVA2FO(pish, pinh->FileHeader.NumberOfSections, datatodecrypt_rva);
		DWORD key = *(DWORD*)&data_oep[0x7a];
		DWORD place_rva = oep_rva + 6 + *(DWORD*)&data_oep[2];  //开门那个call到的地方的位置
		DWORD place_fo = RVA2FO(pish, pinh->FileHeader.NumberOfSections, place_rva);

		DWORD key2 = *(DWORD*)(data + place_fo + 4) + *(DWORD*)(data + place_fo + 0xE);
		DWORD key3 = pinh->OptionalHeader.ImageBase + pinh->OptionalHeader.AddressOfEntryPoint + 6 - *(DWORD*)(data + place_fo + 0x14);

		for (DWORD i = key2; i > 0; --i)
		{
			*(WORD*)(data + temp_fo) ^= key * i - 2 * i;
			temp_fo += 2;
		}

		DWORD key4 = *(DWORD*)(data + RVA2FO(pish, pinh->FileHeader.NumberOfSections, datatodecrypt_rva) + 0x23e);

		DWORD origin_oep_data_VA = key3 + *(DWORD*)&data_oep[7] + key4;

		DWORD origin_oep_data_FO = RVA2FO(pish, pinh->FileHeader.NumberOfSections, origin_oep_data_VA - pinh->OptionalHeader.ImageBase);

		memcpy(data + oep_fo, data + origin_oep_data_FO, 0x7e);

		result = 10;
		goto end4;


	}

	//sality.ae
	if (int pos = MatchSalityAE(data))
	{
		PBYTE pVirusSection = data + pos + 0x1116;

		DWORD sub = *(DWORD*)pVirusSection - 0xe8;

		DWORD test1 = *(DWORD*)(pVirusSection + 4) - sub;

		if (test1 == 0xed815d00) //可以确认是ae变种了
		{
			if (bScanOnly)
			{
				result = 21;
				goto end4;
			}

			DWORD xorkey = *(DWORD*)(pVirusSection + 0x17fa - 0x1116) - sub;
			DWORD len = *(DWORD*)(pVirusSection + 0x288a - 0x1116) - sub;
			
			DWORD sizedata[3] = { 0 };
			sizedata[0] = *(DWORD*)(pVirusSection + 0x249e - 0x1116) - sub;
			sizedata[1] = *(DWORD*)(pVirusSection + 0x24a2 - 0x1116) - sub;
			sizedata[2] = *(DWORD*)(pVirusSection + 0x24a6 - 0x1116) - sub;

			if (*(DWORD*)((BYTE*)sizedata + 3) == *(DWORD*)((BYTE*)sizedata + 7))
			{
				fileoriginalsize = *(DWORD*)((BYTE*)sizedata + 3);
			}

			len ^= xorkey;
			if (len > 0x100)
			{
				result = 23; // 在某些样本中,发现感染不完全,导致数据丢失,此时就不可能修复,只能重装. 一般,len值是6
				goto end4;
			}

			BYTE *temp = (BYTE*)malloc(len / 4 * 4 + 4);
			memcpy(temp, pVirusSection + 0x288e - 0x1116, len / 4 * 4 + 4);

			for (int i = 0; i < (int)len / 4 + 1; ++i)
			{
				*(DWORD*)(temp + i * 4) -= sub;
			}

			DWORD virus_RVA = pos - pish[pinh->FileHeader.NumberOfSections - 1].PointerToRawData + pish[pinh->FileHeader.NumberOfSections - 1].VirtualAddress;

			for (int i = 0; i < 0x400; ++i)  //发现有些入口点附近有jmp会到oep前面,所以得增加一个情况...
			{
				if (*(data + oep_fo + i) == 0xe8)
				{
					DWORD addr_rva = *(DWORD*)(data + oep_fo + i + 1) + i + 5 + pinh->OptionalHeader.AddressOfEntryPoint;
					if (addr_rva >= virus_RVA && addr_rva <= virus_RVA + 0x1000)
					{
						//说明这个位置就是被hook的跳转位置了..
						memcpy(data + oep_fo + i, temp, len);               //他妹的,老是访问异常.. 就是区段表的数据有问题...
						result = 22;
						goto end4;
					}
				}
			}

			//这一部分写在这里而不合起来是为了效率考虑..因为大部分程序应该不会往前跳..

			for (int i = -0x400; i < 0; ++i)
			{
				if (*(data + oep_fo + i) == 0xe8)
				{
					DWORD addr_rva = *(DWORD*)(data + oep_fo + i + 1) + i + 5 + pinh->OptionalHeader.AddressOfEntryPoint;
					if (addr_rva >= virus_RVA && addr_rva <= virus_RVA + 0x1000)
					{
						memcpy(data + oep_fo + i, temp, len);
						result = 22;
						goto end4;
					}
				}
				if (i == -1)
				{
					result = 23;
					goto end4;
				}
			}





		}

	}

	//sality.af  
	if (*(data + oep_fo) == 0xe8)  //af的特征 开门一个call
	{
		DWORD dwJmpDistance = *(DWORD*)(data + oep_fo + 1);
		DWORD RVA_Destination = pinh->OptionalHeader.AddressOfEntryPoint + 5 + dwJmpDistance;
		DWORD FO_Destination = RVA2FO(pish, pinh->FileHeader.NumberOfSections, RVA_Destination);

		if (*(data + FO_Destination) == 0x60)   //pushad       
		{
			//此时可以部分确定是af.. 但仍不一定.. 接下来更详细的判断..跟算法相关,可以绝对判定是af..


			//bj_xxx的基地址只可能是以下两个之一, 因为范围是0~0x3ff
			DWORD dwBase1 = RVA_Destination - RVA_Destination % 0x200;
			DWORD dwBase2 = RVA_Destination - RVA_Destination % 0x200 - 0x200;

			//
			FO_Destination = FO_Destination - FO_Destination % 4 - 4;

			PDWORD pFuck = (DWORD*)(data + FO_Destination);

			if ((*pFuck - *(pFuck - 1)) == (*(pFuck - 1) - *(pFuck - 2)) && (*pFuck != 0))  //可能性进一步提升
			{

				//下面, 是根据dd_bj_xxx[0]为v46与NumberOfBytesWritten的乘积, dd_bj_xxx[4]为v46与NumberOfBytesWritten的和
				//NumberOfBytesWritten是相邻项的差,可以直接算出, 然后根据dd_bj_xxx[4]得到v46, 之后把两个得到的值乘积跟dd_bj_xxx[0]对比.

				DWORD NumberOfBytesWritten = *pFuck - *(pFuck - 1); //这个变量名没什么意思, 就为了跟IDA F5标注的一样

				DWORD FO_base1 = RVA2FO(pish, pinh->FileHeader.NumberOfSections, dwBase1);
				DWORD FO_base2 = RVA2FO(pish, pinh->FileHeader.NumberOfSections, dwBase2);

				DWORD product_of_v46_and_NumberOfBytesWritten1 = *(DWORD*)(data + FO_base1);
				DWORD product_of_v46_and_NumberOfBytesWritten2 = *(DWORD*)(data + FO_base2);

				DWORD sum_of_v46_and_NumberOfBytesWritten1 = *(DWORD*)(data + FO_base1 + 4);
				DWORD sum_of_v46_and_NumberOfBytesWritten2 = *(DWORD*)(data + FO_base2 + 4);

				DWORD v46_1 = sum_of_v46_and_NumberOfBytesWritten1 - NumberOfBytesWritten;
				DWORD v46_2 = sum_of_v46_and_NumberOfBytesWritten2 - NumberOfBytesWritten;

				DWORD v46 = 0, FO_base = 0, dwBase = 0;


				if (product_of_v46_and_NumberOfBytesWritten1 == (DWORD)(v46_1 * NumberOfBytesWritten))
				{
					dwBase = dwBase1;
					FO_base = FO_base1;
					v46 = v46_1;
				}
				else if (product_of_v46_and_NumberOfBytesWritten2 == (DWORD)(v46_2 * NumberOfBytesWritten))
				{
					dwBase = dwBase2;
					FO_base = FO_base2;
					v46 = v46_2;
				}
				else
				{
					; //不是af.. 前两个中都是if.. 进入哪个代表哪个是基地址..
				}

				if (bScanOnly && dwBase != 0)
				{
					//这时候已经可以确定是af了.
					result = 0x3;
					goto end4;
				}

				if (v46 != 0)
				{
					DWORD sizedata[3] = { 0 };
					
					DWORD dd_new_249e = *(DWORD*)(data + FO_base + 0x249e);
					DWORD dd_new_24a2 = *(DWORD*)(data + FO_base + 0x24a2);
					DWORD dd_new_24a6 = *(DWORD*)(data + FO_base + 0x24a6);

					DWORD dd_new_288a = *(DWORD*)(data + FO_base + 0x288a);
					DWORD dd_new_288e = *(DWORD*)(data + FO_base + 0x288e);
					DWORD dd_new_2892 = *(DWORD*)(data + FO_base + 0x2892);
					DWORD dd_new_2896 = *(DWORD*)(data + FO_base + 0x2896);
					DWORD dd_new_289a = *(DWORD*)(data + FO_base + 0x289a);
					DWORD dd_new_289e = *(DWORD*)(data + FO_base + 0x289e);

					DWORD k_289a = dd_new_289e - dd_new_289a;
					if (k_289a & 0x8000'000) //说明采取的是v62==2的方式加密
					{
						k_289a = dd_new_289a - dd_new_289e;
						if ((dd_new_289a - dd_new_289e) == (dd_new_2896 - dd_new_289a - 1))
						{
							DWORD k_288a = 0 - dd_new_289a - (k_289a + 1) - (k_289a + 2) - (k_289a + 3) - (k_289a + 4);
							DWORD k_288e = 0 - dd_new_289a - (k_289a + 1) - (k_289a + 2) - (k_289a + 3);
							DWORD k_2892 = 0 - dd_new_289a - (k_289a + 1) - (k_289a + 2);

							if (((dd_new_288a + k_288a) == 0x955e27fb) || ((dd_new_288a + k_288a) == 1))  //说明是v62==2的加密方式
							{
								//说明正确解密了...

								DWORD dd_old_288e[2] = { 0 };
								dd_old_288e[0] = dd_new_288e + k_288e;
								dd_old_288e[1] = dd_new_2892 + k_2892;

								memcpy(data + oep_fo, dd_old_288e, 5);  //这样就修复完了..

								//增加解密文件大小的部分
								DWORD k_249e = dd_new_289a, k_24a2 = dd_new_289a, k_24a6 = dd_new_289a;
								for (int i = 1; i <= 253; ++i)
								{
									k_24a6 -= (k_289a + i);
								}
								k_24a2 = k_24a6 - (k_289a + 254);
								k_249e = k_24a2 - (k_289a + 255);

								sizedata[0] = dd_new_249e + k_249e;
								sizedata[1] = dd_new_24a2 + k_24a2;
								sizedata[2] = dd_new_24a6 + k_24a6;


								if (*(DWORD*)((BYTE*)sizedata + 3) == *(DWORD*)((BYTE*)sizedata + 7))
								{
									fileoriginalsize = *(DWORD*)((BYTE*)sizedata + 3);
								}

								result = 0x4;
								goto end4;
							}
						}
					}
					else
					{

						if ((dd_new_289e - dd_new_289a) == (dd_new_289a - dd_new_2896 - 1))
						{
							DWORD k_288a = dd_new_289a - (k_289a + 1) - (k_289a + 2) - (k_289a + 3) - (k_289a + 4);
							DWORD k_288e = dd_new_289a - (k_289a + 1) - (k_289a + 2) - (k_289a + 3);
							DWORD k_2892 = dd_new_289a - (k_289a + 1) - (k_289a + 2);

							if (((dd_new_288a - k_288a) == 0x955e27fb) || ((dd_new_288a - k_288a) == 1))
							{
								//说明正确解密了...

								DWORD dd_old_288e[2] = { 0 };
								dd_old_288e[0] = dd_new_288e - k_288e;
								dd_old_288e[1] = dd_new_2892 - k_2892;

								memcpy(data + oep_fo, dd_old_288e, 5);  //这样就修复完了..

								//增加解密文件大小的部分
								DWORD k_249e = dd_new_289a, k_24a2 = dd_new_289a, k_24a6 = dd_new_289a;
								for (int i = 1; i <= 253; ++i)
								{
									k_24a6 -= (k_289a + i);
								}
								k_24a2 = k_24a6 - (k_289a + 254);
								k_249e = k_24a2 - (k_289a + 255);

								sizedata[0] = dd_new_249e - k_249e;
								sizedata[1] = dd_new_24a2 - k_24a2;
								sizedata[2] = dd_new_24a6 - k_24a6;
								

								if (*(DWORD*)((BYTE*)sizedata + 3)== *(DWORD*)((BYTE*)sizedata + 7))
								{
									fileoriginalsize = *(DWORD*)((BYTE*)sizedata + 3);
								}


								result = 0x4;
								goto end4;
							}
						}
					}


				}

				result = 0x4;
				goto end4;
			}





		}

	}

	//sality.ag/bh
	int backupsigpos1 = 0, backupsigpos2 = 0;
	if ((backupsigpos1 = MatchSalityAG(data + pish[pinh->FileHeader.NumberOfSections - 2].PointerToRawData, pish[pinh->FileHeader.NumberOfSections - 2].SizeOfRawData)) ||
		(backupsigpos2 = MatchSalityAG(data + pish[pinh->FileHeader.NumberOfSections - 1].PointerToRawData, pish[pinh->FileHeader.NumberOfSections - 1].SizeOfRawData)))
	{
		int backupsigpos = backupsigpos1 == 0 ? backupsigpos2 : backupsigpos1;

		if (bScanOnly)
		{
			result = 6;
			goto end4;
		}

		int RC4keyoffset = startVM((int)data, pinh->OptionalHeader.AddressOfEntryPoint, pinh->OptionalHeader.ImageBase, pinh->OptionalHeader.SizeOfImage);

		if (RC4keyoffset == 0)
		{
			result = 8;
			goto end4;
		}
		//printf("RC4keyoffset: %08X  ", RC4keyoffset);

		BYTE* bakdata = (BYTE*)malloc(0x3000);
		memcpy(bakdata, data + (RC4keyoffset & 0xffff'fe00), 0x3000);
		int i, j;
		for (i = 0; i <= 31; ++i)
		{
			for (j = 0x0; j <= 0x10061; ++j)
			{
				DWORD temp[4] = { 0 };
				memcpy(temp, &bakdata[0x2446], 16);

				Decrypt_Sality(temp, (unsigned long*)&bakdata[(RC4keyoffset & 0x1ff) + i], j + (0x2446 - 0x1116), 16);  //注意这里的keytable的位置是在新段加v81开始的1~31个字节处可能为起始位置


				if (*(DWORD*)((BYTE*)temp + 7) == pinh->OptionalHeader.AddressOfEntryPoint)  //我这里就解密一个244d处的值比较.
				{
					//printf("key found: %08x,%08x  ", i, j);

					Decrypt_Sality((DWORD*)&bakdata[0x2886], (unsigned long*)&bakdata[(RC4keyoffset & 0x1ff) + i], j + (0x2886 - 0x1116), 8);


					DWORD size = *(DWORD*)&bakdata[0x288a];

					if (size == 1)  //这个值是被替换的字节数,有两种可能,一种是1,另一种就是真实字节数
					{
						result = 0x8;   //这种情况就说未修复成功..
						goto end4;
					}
					else
					{
						Decrypt_Sality((DWORD*)&bakdata[0x288e], (unsigned long*)&bakdata[(RC4keyoffset & 0x1ff) + i], j + (0x288e - 0x1116), size + 8 - (size % 8));  //注意最后个参数要对8取天花板.
						memcpy(data + oep_fo, &bakdata[0x288e], size);
						//printf("入口点0x%x字节已修复\n", size);

						//再解密一下文件大小,重新设置文件大小
						Decrypt_Sality((DWORD*)&bakdata[0x249e], (unsigned long*)&bakdata[(RC4keyoffset & 0x1ff) + i], j + (0x249e - 0x1116), 16);

						if (*(DWORD*)&bakdata[0x24a1] == *(DWORD*)&bakdata[0x24a5])    //
						{
							fileoriginalsize = *(DWORD*)&bakdata[0x24a1];
						}

						result = 0x7;

						PBYTE pFixSig = (PBYTE)backupsigpos;
						memset(pFixSig - 0x4 - 0x9, 0, 0x13);
						goto end4;   //修复成功
					}
				}
				if (j == 0x0)
				{
					j = 0x63;  //直接跳过1~0x63,因为ag不会有这中间的情况.
				}
			}
		}
		result = 0x8;  //走到这边就代表没找到key, 失败了
		goto end4;

	}

	//sality.bg
	if (MatchSalityBG(data))
	{
		if (bScanOnly)
		{
			result = 18;
			goto end4;
		}

		DWORD oep_rva = pinh->OptionalHeader.AddressOfEntryPoint;
		BYTE* data_oep = data + oep_fo;

		DWORD datatodecrypt_rva = oep_rva + *(DWORD*)&data_oep[0xc];
		DWORD temp_fo = RVA2FO(pish, pinh->FileHeader.NumberOfSections, datatodecrypt_rva);
		DWORD key = *(DWORD*)&data_oep[0x68];
		DWORD place_rva = oep_rva + 6 + *(DWORD*)&data_oep[2];  //开门那个call到的地方的位置
		DWORD place_fo = RVA2FO(pish, pinh->FileHeader.NumberOfSections, place_rva);

		DWORD key3 = *(DWORD*)(data + oep_fo + 7);

		for (DWORD i = key3; i > 0; --i)
		{
			*(WORD*)(data + temp_fo) ^= key * i - 2 * i;
			temp_fo += 2;
		}

		BYTE sig[] = { 0x8b,0xf8,0xf3,0xa4,0x33,0xdb };
		if (memcmp(data + RVA2FO(pish, pinh->FileHeader.NumberOfSections, datatodecrypt_rva) + 0x21, sig, sizeof(sig)))
		{
			result = 20;
			goto end4;
		}

		DWORD size = *(DWORD*)(data + RVA2FO(pish, pinh->FileHeader.NumberOfSections, datatodecrypt_rva + 0x17));

		DWORD origin_oep_data_FO = RVA2FO(pish, pinh->FileHeader.NumberOfSections, datatodecrypt_rva + 0x400);

		memcpy(data + oep_fo, data + origin_oep_data_FO, size);

		result = 19;
		goto end4;


	}


end4:
	//区段表恢复
	if (fileoriginalsize)
	{
		for (int i = 0; i < pinh->FileHeader.NumberOfSections; ++i)
		{
			if ((DWORD)fileoriginalsize > pish[i].PointerToRawData&&(DWORD)fileoriginalsize < pish[i].PointerToRawData + pish[i].SizeOfRawData)
			{
				pish[i].SizeOfRawData = fileoriginalsize - pish[i].PointerToRawData;
			}
		}
	}
	
	if (bFreeFlag)
	{
		free(data);
	}
	else
	{
		UnmapViewOfFile(data);
	}


end3:

	CloseHandle(hFileMapping);

	//进行文件大小恢复操作
	if (bScanOnly == FALSE && fileoriginalsize != 0)
	{
		SetFilePointer(hFile, fileoriginalsize, NULL, FILE_BEGIN);
		SetEndOfFile(hFile);
	}
	



end2:
	CloseHandle(hFile);

end1:
	return result;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值