📄 pe_sections.idc
字号:
#include <idc.idc>
/*
// File:
// pe_sections.idc
//
// Created by:
// Atli Gudmundsson (agudmundsson@symantec.com)
//
// Purpose:
// parses the input file and if it is a PE executable does the following:
// - Loads and creates a HEADER section that corresponds to the PE file header.
// - Creates the MZ and PE header structures at the correct place in the header.
// - All fields in the structures, that contain a non zero offset, are resolved.
// - Creates the PE section structures at the correct place in the header.
// - Loads and creates all possible sections.
// - Creates table data structures. Those currently recognizes are:
//
// - the export table.
// - the import table.
// - the resource table (bare format).
// - the debug table.
// - the relocs table.
// - the tls table.
// - the bound import table
//
// Note:
// Be sure to uncheck the 'Make imports section' option, when loading the file for the first time.
// Otherwise most of the data in the import section will be invisible.
//
// Can be unchecked by default from IDA.CFG by specifying PE_MAKE_IDATA = NO.
//
// Usage:
// Just run the script ;).
//
// Fixes/additions
// amg - ??-06-1999 - 1st version.
// amg - 06-03-2000 - a total rewrite, merging two scripts (pe_header.idc --> pe_section.idc),
// also added some comments.
// amg - 07-03-2000 - added xrefs in to the structures (see above) so that you can now travel
// from one structure to the next (e.g. from the MZ header to the PE header)
// This doesn't work for versions less than or equal to v4.02, but it
// won't cause any errors either...
// amg - 01-08-2000 - added an #ifdef because of function incompatability between new and old
// versions of IDA.
// amg - 01-08-2000 - a major rewrite. The script now loads all sections possible.
// amg - 06-08-2000 - added some information messages.
// amg - 06-08-2000 - the script now recognizes when a previously loaded section is interfering
// with the loading of another section and tries to fix that.
// amg - 21-08-2000 - added information about the entry (what it is and in which section)
// amg - 21-08-2000 - added more information messages.
// amg - 29-08-2000 - some bug fixes.
// amg - 30-08-2000 - added support for parsing the header tables.
// amg - 18-09-2000 - resource table added (bare format).
// amg - 18-09-2000 - some bug fixes.
// amg - 21-09-2000 - fixed a minor overside when I was optimizing the script last time ;)
// I forgot to enforce the loading of the HEADER section, silly me :)
// anyway, fixed.
// amg - 21-09-2000 - added a coooool banner that is displayed in the message output.
// amg - 25-09-2000 - we now force the creation of all structures, overstepping some problems
// where IDA has already declared a data element in the middle of the structure.
// amg - 25-09-2000 - the TimeStamp function ULDateToStr() now supports times stamps with the high bit set.
// amg - 25-09-2000 - the script now recognizes when there is no entrypoint in the file.
// amg - 26-09-2000 - the script now parses the relocs tables correctly, even though some of the
// page entries look broken.
// amg - 09-10-2000 - if the header physical size is too small then we just use the virtual size instead.
// amg - 09-10-2000 - names are now created correctly, when requested (overlapping datastructures are destroyed).
// amg - 17-10-2000 - we can now see where each section ends in the file.
// amg - 02-11-2000 - export ordinal comments are now correct (base added)
// amg - 03-11-2000 - we now create all structures, always. Helps debugging apps.
// amg - 03-11-2000 - tls table added.
// amg - 05-11-2000 - minor fixes:
// - to the date function (ULDateToStr()).
// - to the export handling.
// amg - 06-11-2000 - minor enhancement:
// - to the import handling (zero terminated entries).
// amg - 09-11-2000 - added some minor comments to the section flags.
// amg - 10-11-2000 - the script now:
// - skips a particular table if the user presses No.
// - stops parsing tables if the user presses Esc/Cancel.
// amg - 10-11-2000 - fixed the TLS parsing code, we no longer assume we have a callbacks array pointer.
// amg - 10-11-2000 - added better support for user termination requests, when parsing individual tables.
// amg - 14-11-2000 - the script now handles correctly invalid reloc tables, in regard to when finding empty entries in the table.
// amg - 15-11-2000 - the script now displays a message when ever it detects extra data after the image.
// amg - 21-11-2000 - the script now uses a custom Dword() function (LEDword()) since the old one returns 0xff in
// those bytes which would reference into undefined segment memory.
// amg - 21-11-2000 - we now display a warning if the TLS contains callbacks.
// amg - 28-11-2000 - fixed the physical size, when loading sections, it is now adjusted to the file alignment.
// amg - 14-12-2000 - we now use GetInputFilePath() instead of GetInputFile(), to get the location of the original file.
// amg - 18-12-2000 - major modifications (to support the PE_DLLS.IDC script):
// - added a NO_MAIN ifdef so that the script can be called from another script.
// - added a prefix variable (called DLL_name) to all functions.
// amg - 15-01-2001 - added some error checking, regarding section creation. (more is needed though)
// amg - 28-02-2001 - fixed some bugs
// - a most embarrassing bug... forgot a return in the LEWord() function.
// - the above fix exposed another bug in the doResourceTable() function... fixed.
// amg - 28-02-2001 - the script now creates a function and a name on all exports which have no name,
// this allows the script to work better with the PE_DLLS.IDC script.
// amg - 01-03-2001 - the script no longer gives the user the option of selecting which tables to load,
// all tables are loaded by default.
// amg - 06-03-2001 - the script no longer tries to make forwarder entries in the export table into functions,
// instead it makes them into strings.
// amg - 25-04-2001 - the script now supports 'strange' section values, such as when the first section in the
// section table is realy the last section in the file.
// amg - 25-04-2001 - IDA may occasionaly change the default string type from ASCII to something else (such as
// PASCAL), this would play havoc with the strings created by the script. The script now
// bypasses this behaviour, with out affecting IDA.
// amg - 01-05-2001 - re-enabled the asking of whether to load all tables (see change at 01-03-2001), but this time it is
// #ifdefed (Should help when analyzing weird script errors)
// amg - 01-05-2001 - adjusted the import parsing code so that it would actualy terminate the import directory correctly.
// amg - 02-05-2001 - the script is no longer fooled by sections which have a very high RVA (2G+), when determining the
// header virtual size.
// amg - 02-05-2001 - the script now conforms to IDAs way of things when creating section names (replacing spaces with '_')
// amg - 22-05-2001 - the script now behaves correctly when creating sections with ":" in the name, leaving them in there.
// note: this bug would not allow the pe_dlls.idc script to recognize already loaded DLLs (sections)
// amg - 28-05-2001 - bugfix: if all sections vSizes were zero then the HEADER size would be 0x7fffffff.
// amg - 14-06-2001 - bugfix: if phyAddr was 0 and phySize was not then the section was loaded with the header data.
// - windows actualy takes phyAddr == 0 to mean that phySize is also 0
// - additional research revealed that windows truncates phyAddr to a 200h boundary.
// this means that if (0 < phyAddr < 200h) and (phySize != 0) then the section will be
// loaded with the header data.
// amg - 14-06-2001 - interface: minor adjustments to the output of the script (made it more understandable (hopefully ;))
// amg - 22-07-2001 - bound import table now included.
// amg - 04-08-2001 - PE2 format now supported (PE32+ if you will :).
// note: due to IDA limitations the image base is handled as a 32-bit value (high 32-bits are ignored)
// amg - 04-08-2001 - debug directory now supported.
// amg - 07-08-2001 - bugfix: bound import table seems to be constructed of {DWORD, WORD, WORD} nibbles
// amg - 19-08-2001 - bugfix: Native subsystem now behaves correctly in regards to non-sector aligned sections
// amg - 28-08-2001 - bugfix: some runtime packers pack the export table. This would cause the script to go into a very long loop.
// amg - 02-09-2001 - bugfix: the script now asks the user what it should do when it encounters files with weird section offsets.
// amg - 02-09-2001 - interface: image flags will now be different for multivalue flags (reversing all bits when cleared)
// amg - 12-10-2001 - interface: image flags will now be of the following form: mask - bits - info
// amg - 14-10-2001 - interface: if the script encounters a HEADER section it will ask the user if he wants to refresh the section data.
// amg - 14-10-2001 - interface: the script now detects if there is a .reloc section but no relocs and asks if it should try to parse
// it for relocs.
// amg - 14-10-2001 - bugfix: the script is now fully PE2 compliant (any future bugs aside ;)
// amg - 28-10-2001 - bugfix: in Windows 00000000 as an EP is valid, but only if the image is a non-DLL
// amg - 28-10-2001 - interface: image flags will now be of the following form: mask - bit state - info
// you can see I'm having trouble with this one (what do you think is the best one so far ? :)
// amg - 26-11-2001 - bugfix: Windows does not care about the size field of the resource table
// amg - 26-11-2001 - bugfix: TLS code now correctly displays the TLS directory (instead of most of the time leaving it undefined)
// amg - 28-11-2001 - bugfix: offset values are now taken into account when adjusting section sizes to alignment values
// amg - 04-02-2002 - interface: we now add the correct name of an export as a comment (in the export table) if needed.
// amg - 12-03-2002 - minor structural change: doPEtables is now handled with in the LoadSections function
// amg - 12-03-2002 - bugfix: the header structures (MZ, PE) are now created after everything else is done.
// otherwise some tables might actually 'destroy' them...
// amg - 05-04-2002 - enhancement: changed name of ULDToStr() to ULDateToStr()
// created ULDosDateToStr()
// amg - 05-04-2002 - enhancement: we now display Borlands [DOS] time along with Microsoft time for the timestamp field in the pe header.
// amg - 17-05-2002 - enhancement: loading of the image is now in a seperate function (i.e. EXEload()), to better support secondary scripts
// that want to use this one (e.g. the pe_dlls.idc script).
// amg - 13-07-2002 - bugfix:
// - introduced a define for the DLL name seperator (used in pe_dlls.idc as well).
// - we now display the VA for the entry point correctly in PE2 images.
// - we now, correctly, recognize an EP==0 in the HEADER section.
// - better reporting of strangely terminated relocs
// amg - 13-07-2002 - enhancement:
// - we now resolve DLL address collisions (when called from pe_dlls.idc),
// loading the second DLL at a different (free) location.
// - we now apply fixups to all relocated DLLs (most common relocs are supported).
// amg - 15-07-2002 - bugfix:
// - IDA prefixes sections names with an underscore '_' if it starts with a number, section creation now recognizes this.
// - we now recognize a corrupted section count field (too high a value).
// amg - 15-07-2002 - bugfix:
// - addition of image base to 64-bit relocations is now applied correctly (detecting any carry).
//
*/
// Uncomment the following line to allow the user to choose which tables to parse (good for script debugging).
// #define DEBUG_ASK_TABLES
#define MZ_HEADER_STRUCTURE_NAME "S_MZ_HEADER"
#define PE_HEADER_STRUCTURE_NAME "S_PE_HEADER"
#define PE_SECTION_STRUCTURE_NAME "S_PE_SECTION"
#define PE_HEADER_SECTION_NAME "HEADER"
#define DLL_SEPERATOR "_"
// The following define is no longer supported:
//
//#define IDA_IS_OLD
//
// comment the above line if you are using v3.85+
// uncomment the above line if you are using pre v3.85
#ifndef NO_MAIN
static main(void)
{
return EXEload();
}
#endif
static EXEload(void)
{
auto fhandle;
auto MZ_signature, PE_signature;
auto current;
auto PEoffset, imageBase;
auto error;
error = 0;
Message("-------------------------------------------------------------------------------\n\n");
Message(" The PE header parser script.\n Created by Atli Gudmundsson <agudmundsson@symantec.com>\n");
Message("\n");
current = GetInputFilePath();
fhandle = fopen(current, "rb");
while(fhandle == 0)
{
#ifdef IDA_IS_OLD
current = AskFile(current, "Please find the file for me");
#else
current = AskFile(-1, current, "Please find the file for me");
#endif
if(current == 0)
{
error = -1;
break;
}
fhandle = fopen(current, "rb");
}
// fhandle contains a valid handle to an open file.
while(!error)
{
if(MySeek(fhandle, 0, 0) != 0)
{
error = -1;
break;
}
MZ_signature = readshort(fhandle, 0);
if((MZ_signature != 0x4d5a) && (MZ_signature != 0x5a4d))
{
WarningMessage("This is not an MZ executable!");
error = -1;
break;
}
MySeek(fhandle, 0x3c, 0);
PEoffset = readlong(fhandle, 0);
MySeek(fhandle, PEoffset, 0);
PE_signature = readlong(fhandle, 0);
if(PE_signature == 0x4550)
{
imageBase = LoadSections(fhandle, PEoffset, "");
if(imageBase == -1)
{
error = -1;
}
break;
}
else
{
WarningMessage("This is not a PE executable!");
error = -1;
break;
}
}
fclose(fhandle);
if(!error)
{
return imageBase;
}
else
{
return BADADDR;
}
}
static WarningMessage(outString)
{
Message(outString + "\n");
Warning(outString);
}
static CleanSectName(sect_name)
{
auto retval;
retval = "";
if(sect_name != "")
{
auto i, str_len;
str_len = strlen(sect_name);
i = 0;
do
{
auto letter, sub_str;
sub_str = substr(sect_name, i, i+1);
if((sub_str != ":") && (sub_str != ".") && ((sub_str < "0") || ((sub_str > "9") && (sub_str < "A") || (sub_str > "Z") && ((sub_str < "a") || (sub_str > "z")))))
{
sub_str = "_";
}
retval = retval + sub_str;
i++;
}
while(i != str_len);
}
return retval;
}
/*
// Function:
// CreateSection
// Purpose:
// Creates a virtual section, expanding or adjusting already existing sections
// as needed.
// Input:
// SectionName
// SectionStart - VA of the start of the section
// vSize - the requested virtual size of the section
// phyAddr - offset of this sections physical block, in the file
// phySize - size of this sections physical block, in the file
// loadData - specifies wether the function should actually read the data from the file.
// Returns:
// nothing
// Notes:
// The function also prints messages that tell the user if anything unusual happend.
*/
static CreateSection(fhandle, SectionName, SectionStart, vSize, phyAddr, phySize, loadData)
{
auto SectionBase;
auto question, answer;
SectionName = CleanSectName(SectionName);
#if defined(DEBUG_THIS)
Message(form("%s: [%08X, %08X] --> [%08X, %08X]\n", SectionName, phyAddr, phySize, SectionStart, vSize));
#endif
SectionBase = SectionStart;
if(vSize != 0)
{
auto SectionEnd;
SectionEnd = SectionStart + vSize;
while(SectionStart < SectionEnd)
{
if(SegStart(SectionStart) != BADADDR)
{
// A section, at the specified address, already exists.
if((SegName(SectionStart) == SectionName) || (SegName(SectionStart) == "_" + SectionName)) // if name starts with a number then IDA prefixes it with an '_'
{
// A section with the given name already exists at this address.
if(SegEnd(SectionStart) >= SectionEnd)
{
// cool, nothing more needed
Message(" %s (%.8X - %.8X) section already exists.\n", SegName(SectionStart), SegStart(SectionStart), SegEnd(SectionStart));
if((SegStart(SectionStart) != SectionStart) || (SegEnd(SectionStart) != SectionEnd))
{
Message(" and already spans the addresses (%.8X - %.8X).\n", SectionStart, SectionEnd);
}
SectionStart = SectionEnd;
break;
}
else
{
// must expand the section upwards.
SegBounds(SectionStart, SegStart(SectionStart), SectionEnd, 1);
SegRename(SectionStart, SectionName);
Message(" %s section found at %.8X, expanded to (%.8X - %.8X).\n", SectionName, SectionStart, SegStart(SectionStart), SegEnd(SectionStart));
}
}
else
{
// An unknown section, at the specified address, already exists.
Message(" %s (%.8X - %.8X) section already spans the address %.8X.\n", SegName(SectionStart), SegStart(SectionStart), SegEnd(SectionStart), SectionStart);
Message(" %s created at the next available address.\n", SectionName);
SectionStart = SegEnd(SectionStart);
continue;
}
}
else
{
// no section has this start address in itself.
SegCreate(SectionStart, SectionEnd, 0, 1, saRelPara, scPub);
SegRename(SectionStart, SectionName);
}
// SectionStart is always inside a section at this point
// SegEnd(SectionStart) == SectionEnd OR SegEnd(SectionStart) is inside a section
if(SegEnd(SectionStart) < SectionEnd)
{
auto temp;
// hmmm, unable to do the entire segment
// must have another segment interfering
temp = SegEnd(SectionStart);
if(SegName(temp) == SectionName)
{
// they have the same names, so let's merge them
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -