实习期的一个任务, 写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;
}