脫Remote Administrator v2.0的殼 (8千字)

看雪資料發表於2001-06-24

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;
}

相關文章