juntalis Newbie cheater Reputation: 2
Joined: 13 Mar 2013 Posts: 12
|
Posted: Sat Apr 16, 2016 4:42 am Post subject: Parsing data from the PE Headers |
|
|
I wrote a script a while back that required me to change some logic depending on the executable's checksum, so I decided to write up a quick example:
Code: |
--- Reverse a keyed table of numeric values and add the resulting pairs
-- to the original table.
-- @tparam {[string]=int,...} kvargs target keyed table
local function enum(kvargs)
local result = {}
local key = next(kvargs)
while key ~= nil do
local value = kvargs[key]
result[key] = value
result[value] = key
key = next(kvargs, key)
end
return result
end
---
-- Potential values for OptionalHeader.Subsystem
-- @table IMAGE_SUBSYSTEM
-- @tfield[value=0x00] int UNKNOWN Value of IMAGE_SUBSYSTEM_UNKNOWN
-- @tfield[value=0x01] int NATIVE Value of IMAGE_SUBSYSTEM_NATIVE
-- @tfield[value=0x02] int WINDOWS_GUI Value of IMAGE_SUBSYSTEM_WINDOWS_GUI
-- @tfield[value=0x03] int WINDOWS_CUI Value of IMAGE_SUBSYSTEM_WINDOWS_CUI
-- @tfield[value=0x05] int OS2_CUI Value of IMAGE_SUBSYSTEM_OS2_CUI
-- @tfield[value=0x07] int POSIX_CUI Value of IMAGE_SUBSYSTEM_POSIX_CUI
-- @tfield[value=0x08] int NATIVE_WINDOWS Value of IMAGE_SUBSYSTEM_NATIVE_WINDOWS
-- @tfield[value=0x09] int WINDOWS_CE_GUI Value of IMAGE_SUBSYSTEM_WINDOWS_CE_GUI
-- @tfield[value=0x0A] int EFI_APPLICATION Value of IMAGE_SUBSYSTEM_EFI_APPLICATION
-- @tfield[value=0x0B] int EFI_BOOT_SERVICE_DRIVER Value of IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
-- @tfield[value=0x0C] int EFI_RUNTIME_DRIVER Value of IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
-- @tfield[value=0x0D] int EFI_ROM Value of IMAGE_SUBSYSTEM_EFI_ROM
-- @tfield[value=0x0E] int XBOX Value of IMAGE_SUBSYSTEM_XBOX
-- @tfield[value=0x10] int WINDOWS_BOOT_APPLICATION Value of IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION
IMAGE_SUBSYSTEM = enum {
UNKNOWN = 0x00, -- IMAGE_SUBSYSTEM_UNKNOWN
NATIVE = 0x01, -- IMAGE_SUBSYSTEM_NATIVE
WINDOWS_GUI = 0x02, -- IMAGE_SUBSYSTEM_WINDOWS_GUI
WINDOWS_CUI = 0x03, -- IMAGE_SUBSYSTEM_WINDOWS_CUI
OS2_CUI = 0x05, -- IMAGE_SUBSYSTEM_OS2_CUI
POSIX_CUI = 0x07, -- IMAGE_SUBSYSTEM_POSIX_CUI
NATIVE_WINDOWS = 0x08, -- IMAGE_SUBSYSTEM_NATIVE_WINDOWS
WINDOWS_CE_GUI = 0x09, -- IMAGE_SUBSYSTEM_WINDOWS_CE_GUI
EFI_APPLICATION = 0x0A, -- IMAGE_SUBSYSTEM_EFI_APPLICATION
EFI_BOOT_SERVICE_DRIVER = 0x0B, -- IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
EFI_RUNTIME_DRIVER = 0x0C, -- IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
EFI_ROM = 0x0D, -- IMAGE_SUBSYSTEM_EFI_ROM
XBOX = 0x0E, -- IMAGE_SUBSYSTEM_XBOX
WINDOWS_BOOT_APPLICATION = 0x10 -- IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION
}
do
--- Local cache
local _L = {
lpNtHdrs = {},
maGetters = {},
}
--- Field offsets
local NT_HEADER_FADDR_OFFSET = 0x3C -- IMAGE_DOS_HEADER.e_lfanew
local OPTIONAL_HEADER_OFFSET = 0x18 -- IMAGE_NT_HEADERS.OptionalHeader
local IMAGE_CHECKSUM_OFFSET = 0x40 -- IMAGE_OPTIONAL_HEADER.CheckSum
local IMAGE_SUBSYSTEM_OFFSET = 0x44 -- IMAGE_OPTIONAL_HEADER.Subsystem
local readDword = readInteger
local function readWord(address)
local bytes = readBytes(address, 2, true)
return byteTableToWord(bytes)
end
local function moduleAddressGetter(module)
-- Check the cache. If non-existent, generate our
-- handler and cache it.
if not _L.maGetters[module] then
local prefix = module .. '+'
_L.maGetters[module] = function(offset)
if type(offset) == 'number' then
offset = string.format('%X', offset)
end
return getAddress(prefix .. offset)
end
end
return _L.maGetters[module]
end
local function getNtHeader(module)
-- Module name is case-insensitive
module = string.lower(module)
-- Check the cache. If non-existent, resolve the address
-- of our NT_HEADER and cache it.
if not _L.lpNtHdrs[module] then
local moduleAddress = moduleAddressGetter(module)
local address = moduleAddress(NT_HEADER_FADDR_OFFSET)
local offset = readDword(address)
_L.lpNtHdrs[module] = moduleAddress(offset)
end
return _L.lpNtHdrs[module]
end
local function getOptionalHeader(module)
return getNtHeader(module) + OPTIONAL_HEADER_OFFSET
end
--- Get value of IMAGE_NT_HEADERS.OptionalHeader.CheckSum
local function getCheckSum(module)
local address = getOptionalHeader(module) + IMAGE_CHECKSUM_OFFSET
local checksum = readDword(address)
return string.format('%08X', checksum)
end
--- Get value of IMAGE_NT_HEADERS.OptionalHeader.Subsystem
local function getSubsystem(module)
local address = getOptionalHeader(module)
local subsystem = readWord(address + IMAGE_SUBSYSTEM_OFFSET)
return IMAGE_SUBSYSTEM[subsystem], subsystem
end
_G.getModuleCheckSum = getCheckSum
_G.getModuleSubsystem = getSubsystem
end
local moduleName = 'mygame.exe'
print('CheckSum', '=>', getModuleCheckSum(moduleName))
print('Subsystem', '=>', string.format('%s [%02X]', getModuleSubsystem(moduleName)))
|
Example output:
Code: |
CheckSum => 02C2154E
Subsystem => WINDOWS_GUI [02]
|
If I ever find the time and motivation, I'd like to write a more sophisticated example that parses the section headers and registers symbols according to their virtual addresses. (ex: mygame__rdata_section)
|
|