📄 module.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
#include "module.h"
#include "..\parser\token.h"
#include "compress.h"
#include "romsig.h"
/*****************************************************************************
get_map_symbols()
in:
bool return mangled names if profile_all is set
MemoryList &memory_list
out:
boolean value indicating success
desc:
retrieves all the info for the symbols from the .map file, if it exists
*****************************************************************************/
bool Module::get_map_symbols(bool profile_all, MemoryList &memory_list){
string map_file = m_release_path;
map_file.replace(map_file.rfind('.'), 4, ".map");
// used to make sure the file exists
if(GetFileAttributes(map_file.c_str()) == -1)
return true; // don't care if there is a map file or not
// open
ifstream file(map_file.c_str(), ios::in);
if(file.bad()){
cerr << "Error: Could not open '" << map_file << "' for reading\n";
return false;
}
string line;
// skip to start of symbols
while(!file.eof() && line.find("Publics by Value") == string::npos)
getline(file, line, '\n');
// start processing and seaching tokens
string token;
while(!file.eof()){
getline(file, line, '\n');
// skip lines with no symbol information
if(line.substr(0, 3) != " 00" || line[5] != ':')
continue;
// envvar for backwards compatability
static string delim = getenv("romimagenotrunc") || profile_all ? " " : " @";
token = Token::get_token(line, 21, delim);
DWORD sec_number = Token::get_hex_value(line.substr(1, 4)) - 1;
DWORD sec_offset = Token::get_hex_value(line.substr(6, 8)) + page_size();
if(line.find(" f ") != string::npos){
Function f;
f.name = token;
f.address = Token::get_hex_value(line.substr(6, 8));
m_profile.m_function_list.push_back(f);
}
else if(sec_number >= 0 && sec_number < m_o32_list.size() && !m_o32_list[sec_number].is_writable() && token[0] != '?'){
Function f;
f.name = token;
f.address = Token::get_hex_value(line.substr(6, 8));
m_profile.m_function_list.push_back(f);
}
check_special_symbol(token, sec_number, sec_offset, memory_list);
}
return true;
}
/*****************************************************************************
check_special_symbol()
in:
MemoryList &memory_list
out:
none
desc:
looks for certain special symbol names to set state variables
*****************************************************************************/
void Module::check_special_symbol(string token, DWORD o32_section, DWORD offset, MemoryList &memory_list){
if(token[0] == '_')
token.erase(0, 1);
if(token == "RomExt")
m_ROM_extensions = memory_iterator()->address() + offset + m_load_offset;
if(token == "ResetVector")
m_reset_vector = (DWORD *)(m_o32_list[0].data.ptr() + offset - page_size());
if(token == "ResetVectorEnd")
m_reset_vector_end = (DWORD *)(m_o32_list[0].data.ptr() + offset - page_size());
if(token == "ResetVectorAddr")
m_reset_vector_addr = (DWORD *)(m_o32_list[0].data.ptr() + offset - page_size());
if(token == "KdDebuggerEnabled")
m_flags |= FLAG_KERNEL_DEBUGGER;
if(is_kernel()){
if(token == "pTOC"){
m_TOC_offset = offset + m_load_offset; // doesn't get load offset added, because only compared with rva later
LAST_PASS_PRINT printf("Found pTOC at %08x\n", m_TOC_offset);
}
if(needs_signing()){
if(token == "OEMIoControl")
s_oem_io_control = offset + m_load_offset - page_size();
}
if(o32_section != -1)
for(MemoryList::iterator mem_itr = memory_list.begin(); mem_itr != memory_list.end(); mem_itr++)
if(mem_itr->type() == FIXUPVAR_TYPE)
if(mem_itr->name() == token){
static char *debug_show = (debug_show = getenv("ri_debug_info")) ? strstr(debug_show, "fixupvar") : NULL;
mem_itr->fixupvar_section = o32_section;
mem_itr->Address::set(offset + m_load_offset - page_size(), mem_itr->length());
if(debug_show) printf("FixupVar %s is at %08x\n", mem_itr->name().c_str(), mem_itr->address());
}
}
}
/*****************************************************************************
rva2ptr()
in:
DWORD relative vertual address to resolve
out:
DWORD address of data - NULL indicates failure
desc:
takes the rva and searches to see which objects range it falls into and
then returns a pointer the the apropriate location in the data
*****************************************************************************/
DWORD Module::rva2ptr(DWORD rva) const{
for(O32List::const_iterator o32_itr = m_o32_list.begin(); o32_itr != m_o32_list.end(); o32_itr++)
if((!o32_itr->o32_psize && o32_itr->o32_rva == rva) ||
(o32_itr->o32_rva <= rva && rva < o32_itr->o32_rva + o32_itr->o32_psize))
return (DWORD)o32_itr->data.ptr() + rva - o32_itr->o32_rva;
fprintf(stderr, "Error: Could not find rva %08x in %s\n", rva, m_name.c_str());
for(DWORD i = 0; i < m_o32_list.size(); i++)
fprintf(stderr, "o32[%d].o32_rva = %08x (len = %08x)\n", i, m_o32_list[i].o32_rva, m_o32_list[i].o32_psize);
assert(!"rva2ptr() error");
return 0;
}
/*****************************************************************************
nk_fixup_rva()
in:
DWORD fixup_addr - address to be fixed up
DWORD base - base memory offset
out:
DWORD - fixed up address or origional if no fixup found
desc:
fixes up kernel rva's
*****************************************************************************/
DWORD Module::fixup_rva_nk(DWORD fixup_addr){
DWORD orig_fixup_addr = fixup_addr;
// Actual section starting rva after readonly sections have been moved to start of image
DWORD next_avail = m_o32_list[0].o32_rva;
fixup_addr = (fixup_addr & 0x00FFFFFF) - (m_vreloc & 0x00FFFFFF);
for(O32List::iterator o32_itr = m_o32_list.begin(); o32_itr != m_o32_list.end() && fixup_addr >= o32_itr->o32_rva + o32_itr->max_size(); o32_itr++){
// address found
if((o32_itr + 1) != m_o32_list.end() && fixup_addr < (o32_itr + 1)->o32_rva)
break;
if(!o32_itr->is_writable())
next_avail += align_page(o32_itr->min_size());
}
if(o32_itr == m_o32_list.end()){
#if 0 // debug check for sections
static bool once = true;
if(once){
fprintf(stderr, "Error: Could not find rva %08x in %s\n", fixup_addr, m_name.c_str());
for(int i = 0; i < m_o32_list.size(); i++)
fprintf(stderr, "o32[%d].o32_rva = %08x (len = %08x)\n", i, m_o32_list[i].o32_rva, m_o32_list[i].o32_psize);
once = false;
}
#endif
fprintf(stderr, "Section not found for %8x fixing up %s\n", fixup_addr, name().c_str());
return orig_fixup_addr;
}
if(!o32_itr->is_writable())
return orig_fixup_addr - (o32_itr->o32_rva - next_avail);
if(fixup_addr == m_TOC_offset){
fprintf(stderr, "NKFixupRVA: target %8x is in section %s offset=%8x - is TOC not changed!\n",
fixup_addr, m_name.c_str(), o32_itr->o32_rva + o32_itr->o32_dataptr);
return orig_fixup_addr;
}
fixup_addr = fixup_addr - o32_itr->o32_rva + o32_itr->o32_dataptr;
// Reset top bit to be same as original fixup address
// Note: this scheme assumes a 1:1 physical to virtual address correspondence, where 0x80000000 <-> 0x00000000
if(!(orig_fixup_addr & 0x80000000))
fixup_addr &= 0x7fffffff;
return fixup_addr;
}
/*****************************************************************************
*****************************************************************************/
DWORD Module::get_rva_delta(const FixupInfo &kernel_fixup, DWORD rva_delta){
if(m_o32_list[0].is_writable())
assert(!"Error: First section of NK must be READONLY!");
DWORD next_avail = m_o32_list[0].o32_rva; // actual section starting rva after relocate_image() is called
for(O32List::iterator o32_itr = m_o32_list.begin(); o32_itr != m_o32_list.end() && (kernel_fixup.RvaTarget < o32_itr->o32_rva || kernel_fixup.RvaTarget >= o32_itr->o32_rva + o32_itr->o32_vsize); o32_itr++){
if((o32_itr + 1) != m_o32_list.end() && kernel_fixup.RvaTarget >= o32_itr->o32_rva && kernel_fixup.RvaTarget < (o32_itr + 1)->o32_rva)
break;
if(!o32_itr->is_writable())
next_avail += align_page(o32_itr->min_size());
}
if(o32_itr == m_o32_list.end()){
fprintf(stderr, "Section not found for %8x\n", kernel_fixup.RvaTarget);
// assert(0); // I don't think a return is apropriate here! but I'm going to let it go for now.
}
if(!o32_itr->is_writable()){
if(o32_itr->o32_rva != next_avail)
return rva_delta - (o32_itr->o32_rva - next_avail);
return rva_delta;
}
return (DWORD)o32_itr->data.ptr() - m_e32.e32_vbase - o32_itr->o32_rva;
}
/*****************************************************************************
addr_from_eat()
in:
module_list - modules that may be needed for recursive searching
DWORD eat - eat address to find
out:
DWORD - result or zero if not found
desc:
get the address from the export address table
*****************************************************************************/
DWORD Module::addr_from_eat(const ModuleList &module_list, DWORD eat) const{
const DWORD SECTION_MASK = 0x03F;
const DWORD VA_SECTION = 25;
if(eat < m_e32.e32_unit[EXP].rva || eat >= m_e32.e32_unit[EXP].rva + m_e32.e32_unit[EXP].size){
DWORD ptr = m_vreloc;
if(ptr & 0x80000000)
ptr &= ~(SECTION_MASK << VA_SECTION);
return eat + ptr;
}
string filename = (char *)rva2ptr(eat);
string str = filename;
if(filename.find('.')){
filename.erase(filename.find('.'));
str.erase(0, str.find('.') + 1);
}
for(ModuleList::const_iterator mod_itr = module_list.begin(); mod_itr != module_list.end(); mod_itr++){
string modname = mod_itr->name();
modname = modname.substr(0, modname.find('.'));
if(modname == filename)
if(str[0] == '@')
return mod_itr->resolve_imp_ord(module_list, atoi(str.c_str() + 1));
else
return mod_itr->resolve_imp_str(module_list, str);
}
cerr << "Error: Unresolved external: " << filename << endl;
return 0;
}
/*****************************************************************************
resolve_imp_ord()
in:
module_list - modules that may be needed for recursive searching
DWORD ord - ordinal to find the address for
out:
DWORD - address of function for ordinal or NULL for failure
desc:
find the address of a function specified by ordinal number
*****************************************************************************/
DWORD Module::resolve_imp_ord(const ModuleList &module_list, DWORD ord) const{
// no rva nothing to resolve
if(!m_e32.e32_unit[EXP].rva)
return 0;
ExpHdr *expptr = (ExpHdr *)rva2ptr(m_e32.e32_unit[EXP].rva);
DWORD *eatptr = (DWORD *)rva2ptr(expptr->exp_eat);
DWORD hint = ord - expptr->exp_ordbase;
DWORD ret = 0;
if(hint <= expptr->exp_eatcnt)
ret = addr_from_eat(module_list, eatptr[hint]);
if(!ret){
cerr << "Error: Can't find import " << ord << " in " << m_name << endl;
}
return ret;
}
/*****************************************************************************
resolve_imp_str()
in:
module_list - modules that may be needed for recursive searching
string str - name of function to resolve
out:
DWORD - address of function named, NULL for failure
desc:
resolve a funciton by name
*****************************************************************************/
DWORD Module::resolve_imp_str(const ModuleList &module_list, const string &str) const{
// no rva nothing to resolve
if(!m_e32.e32_unit[EXP].rva)
return 0;
ExpHdr *expptr = (ExpHdr *)rva2ptr(m_e32.e32_unit[EXP].rva);
char **nameptr = (char **)rva2ptr(expptr->exp_name);
DWORD *eatptr = (DWORD *)rva2ptr(expptr->exp_eat);
WORD *ordptr = (WORD *)rva2ptr(expptr->exp_ordinal);
for(unsigned i = 0; i < expptr->exp_namecnt; i++)
if(str == (char *)rva2ptr((DWORD)nameptr[i]))
break;
// found it
if(i != expptr->exp_namecnt)
return addr_from_eat(module_list, eatptr[ordptr[i]]);
cerr << "Error: Can't find import " << str << " in " << m_name << endl;
return 0;
}
/*****************************************************************************
resolve_imp_hint_ord()
in:
module_list - modules that may be needed for recursive searching
DWORD hint - type of string provided for the hint
string str - using in cojunction with a hint to determin function resolution
out:
DWORD - address of function, NULL indicates failure
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -