Remote Administrator v2.0
http://www.famatech.com/radmin20.zip : size 1,482,243 bytes
Radmin.exe : size 1,032,192 bytes
你是怎么知道它是用Armadillo加的壳?fiv245报是VC6的,但是它的确是经过了处理,OEP是 ACEBFC。
加壳程序并不像其它的把被还原出来数据放到已预定下来的section里,而是放在动态分配出来的空间,
所以pedump dump出来的exe也不过是加壳还原程序,这真的让我们一下子束手无策!
bpmb ds:acebfc w,发现 1401422 的 CALL 1401BE0 就是还原代码到OEP的。
再细看加壳还原程序就知道有六个 section 通过上面的call被还原了。
分别是:
RVA size alignment
1000 3822A 39000
3A000 4C7A 5000
3F000 1E13C 1F000
5E000 447C 5000
63000 400 1000
64000 11C18D 11D000
[0140FE30] 存放原image base : AA0000
往上看在 140137E 有 CALL 1401BE0,这里是“还原”PIMAGE_NT_HEADERS32,好像什么都有了,
将 AA0000 到 AA0000 + 64000 + 11D000 (section alignment是1000) dump出来不就行了吗?
唔?没有图标?用Peditor看section table,才五个section,什么都是空的,看directory的
resource又说出错,惨了,初步断定无药可救!
再用eXeScope看原Radmin.exe,在resource里看到有ICON, MENU, BITMAP等等,反正算是齐全了。
对,就是差这些了,把这些resource加到刚才dump出来的exe里去!
directory里的resource RVA : 11000, size : EB498,不就是整个.rsrc section吗。
好,先把dump出来exe的entry point改为 2EBFC, image base改为 AA0000,directory 里所有的RVA, size先全改为0
再将每个section的正确值修改回去,如上列出的
第一个section
name : (随便)
Virtual Address : 1000
Virtual Size : 39000
Raw Offset : 1000
Raw Size : 39000
Characteristics : E00000E0
如此类推,最后加上我们的.rsrc,resource section. RVA 181000, size 11D000,改directory的
resource RVA 181000, size EC000。
用Hex workshop将Radmin.exe的.rsrc section(Offset 10000, size EC000) copy出来,
追加到dump出来exe的最后,存盘,咦?依然未见图标??
再用Peditor看directory的resource的详细列表,ICON, MENU, BITMAP等等都有了,选中cursor
下的21子项,在Item Info 组合框中的 RVA to Data 是 393A8,size : 134。
哦,原来RVA 393A8 并不是指向我们新加的.rsrc section。
最笨的方法就是把这些RVA to Data逐个修正过来,可是Peditor不可以修改该值,天啊,天晓得在.rsrc这堆“垃圾”里改哪个值才是!
还是写程序吧,幸好在找有关resource结构的时候找到有列举resource的程序,修改一下就可以用了。
以下程序是裁剪并修改MSDN 的 Peering Inside the PE: A Tour of the Win32 Portable Executable
File Format里的程序,
(那些printf 我都没有去掉), fix_value 就是要修正的量。
new section RVA
old section RVA alignment diff
|
|
|
DWORD fix_value = 0x181000 -
0x10000 - 0x1000;
resDataEntry->OffsetToData = resData_RVA + fix_value;
先把.rsrc整个section save as 为res.bin, 程序是将res.bin map到内存,再修改OffsetToData,
记住运行一次该程序就可以了,再将该res.bin粘贴回dump出来的exe去,exe图标就会出现了。
最后是import table的重建了(唉,太累了!!!)。
在Import REConstructor的OEP里填2EBFC,get import不成功,原因是OEP所对应的image base 是AA0000,
而不是01400000,在load radmin.exe, trw里下 mod32. 显示:
hMod PEHeader Base Module No
ModuleName
---- -------- -------- -------- -- ----------
xxxx 81991A58 01400000 xxxxxxxx xx RADMIN.EXE
d ds:81991A58 + 34 处就是image base 01400000,改其为 00AA0000
再在Import REConstructor 里get import就成功了,只有一个1401000不知道, 暂定为GetModuleFileNameA。
(后来没仔细看对不对了),至此脱壳完成。程序有自检,这里就不说了。
/* fixres.cpp */
/* cl fixres.cpp user32.lib */
#include <stdio.h>
#include <windows.h>
BOOL bFixIt = TRUE;
DWORD fix_value = 0x181000 - 0x10000 - 0x1000;
// Function prototype (necessary because two functions recurse)
void DumpResourceDirectory
(
PIMAGE_RESOURCE_DIRECTORY resDir, DWORD resourceBase,
DWORD level, DWORD resourceType
);
// The predefined resource types
char *SzResourceTypes[] = {
"???_0", "CURSOR", "BITMAP", "ICON", "MENU", "DIALOG", "STRING", "FONTDIR",
"FONT", "ACCELERATORS", "RCDATA", "MESSAGETABLE", "GROUP_CURSOR",
"???_13", "GROUP_ICON", "???_15", "VERSION"
};
// Get an ASCII string representing a resource type
void GetResourceTypeName(DWORD type, PSTR buffer, UINT cBytes)
{
if ( type <= 16 )
strncpy(buffer, SzResourceTypes[type],
cBytes);
else
wsprintf(buffer, "%X", type);
}
//
// If a resource entry has a string name (rather than an ID), go find
// the string and convert it from unicode to ascii.
//
void GetResourceNameFromId
(
DWORD id, DWORD resourceBase, PSTR buffer, UINT cBytes
)
{
PIMAGE_RESOURCE_DIR_STRING_U prdsu;
// If it's a regular ID, just format it.
if ( !(id & IMAGE_RESOURCE_NAME_IS_STRING) )
{
wsprintf(buffer, "%X", id);
return;
}
id &= 0x7FFFFFFF;
prdsu = (PIMAGE_RESOURCE_DIR_STRING_U)(resourceBase + id);
// prdsu->Length is the number of unicode characters
WideCharToMultiByte(CP_ACP, 0, prdsu->NameString, prdsu->Length,
buffer, cBytes, 0, 0);
buffer[ min(cBytes-1,prdsu->Length) ] = 0; //
Null terminate it!!!
}
//
// Dump the information about one resource directory entry. If the
// entry is for a subdirectory, call the directory dumping routine
// instead of printing information in this routine.
//
void DumpResourceEntry
(
PIMAGE_RESOURCE_DIRECTORY_ENTRY resDirEntry,
DWORD resourceBase,
DWORD level
)
{
UINT i;
PIMAGE_RESOURCE_DATA_ENTRY resDataEntry;
DWORD resData_RVA;
char nameBuffer[128];
if ( resDirEntry->OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY
)
{
DumpResourceDirectory( (PIMAGE_RESOURCE_DIRECTORY)
((resDirEntry->OffsetToData
& 0x7FFFFFFF) + resourceBase),
resourceBase, level,
resDirEntry->Name);
return;
}
// Spit out the spacing for the level indentation
for ( i=0; i < level; i++ )
printf(" ");
if ( resDirEntry->Name & IMAGE_RESOURCE_NAME_IS_STRING
)
{
GetResourceNameFromId(resDirEntry->Name,
resourceBase, nameBuffer,
sizeof(nameBuffer));
printf("Name: %s Offset: %08X\n",
nameBuffer, resDirEntry->OffsetToData);
}
else
{
printf("ID: %08X Offset: %08X\n",
resDirEntry->Name,
resDirEntry->OffsetToData);
}
resDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)(resDirEntry->OffsetToData
+ resourceBase);
resData_RVA = resDataEntry->OffsetToData;
printf("Resource data RVA is : %08X\n", resData_RVA);
if ( bFixIt )
resDataEntry->OffsetToData = resData_RVA
+ fix_value;
}
//
// Dump the information about one resource directory.
//
void DumpResourceDirectory
(
PIMAGE_RESOURCE_DIRECTORY resDir,
DWORD resourceBase,
DWORD level,
DWORD resourceType
)
{
PIMAGE_RESOURCE_DIRECTORY_ENTRY resDirEntry;
char szType[64];
UINT i;
// Spit out the spacing for the level indentation
for ( i=0; i < level; i++ )
printf(" ");
// Level 1 resources are the resource types
if ( level == 1 && !(resourceType & IMAGE_RESOURCE_NAME_IS_STRING)
)
{
GetResourceTypeName( resourceType, szType,
sizeof(szType) );
}
else // Just print out the regular id or
name
{
GetResourceNameFromId( resourceType, resourceBase,
szType,
sizeof(szType) );
}
printf(
"ResDir (%s) Named:%02X ID:%02X TimeDate:%08X
Vers:%u.%02u Char:%X\n",
szType, resDir->NumberOfNamedEntries,
resDir->NumberOfIdEntries,
resDir->TimeDateStamp, resDir->MajorVersion,
resDir->MinorVersion,resDir->Characteristics);
resDirEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resDir+1);
for ( i=0; i < resDir->NumberOfNamedEntries; i++, resDirEntry++
)
DumpResourceEntry(resDirEntry, resourceBase,
level+1);
for ( i=0; i < resDir->NumberOfIdEntries; i++, resDirEntry++
)
DumpResourceEntry(resDirEntry, resourceBase,
level+1);
}
//
// Top level routine called to dump out the entire resource hierarchy
//
void DumpResourceSection( LPVOID pmapbase )
{
IMAGE_RESOURCE_DIRECTORY *resDir;
resDir = (IMAGE_RESOURCE_DIRECTORY*) pmapbase;
printf("Resources\n");
DumpResourceDirectory(resDir, (DWORD)resDir, 0, 0);
}
int main( void )
{
HANDLE hfile, hMap;
LPVOID p_MapFile;
if ( (hfile = CreateFile("res.bin", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ
+ FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE
)
{
printf("Can not open file res.bin\n");
exit(1);
}
if ( (hMap = CreateFileMapping(hfile, NULL, PAGE_READWRITE, 0, 0, NULL))
== NULL )
{
CloseHandle( hfile );
printf("Can not create file mapping!\n");
exit(1);
}
if ( (p_MapFile = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0)) == NULL
)
{
CloseHandle( hfile );
CloseHandle( hMap );
printf("Can not map file!\n");
exit(1);
}
__try
{
DumpResourceSection( p_MapFile );
}
__except(1)
{
printf("Error when processing file!\n");
}
UnmapViewOfFile( p_MapFile );
CloseHandle( hfile );
CloseHandle( hMap );
return 0;
}
- 标 题:脱Remote Administrator v2.0的壳 (8千字)
- 作 者:fs0
- 时 间:2001-6-24 19:29:59
- 链 接:http://bbs.pediy.com