1 #include "pe_analyzer.h"
2 #include "pe_utils.h"
3 #include "pe_constants.h"
4 #include "../../support/rtti/msvc/rtti_msvc.h"
5 
6 #define IMPORT_NAME(library, name) PEUtils::importName(library, name)
7 #define IMPORT_TRAMPOLINE(library, name) ("_" + IMPORT_NAME(library, name))
8 #define ADD_WNDPROC_API(argidx, name) m_wndprocapi.emplace_front(argidx, name)
9 
10 namespace REDasm {
11 
PEAnalyzer(const PEClassifier * classifier,DisassemblerAPI * disassembler)12 PEAnalyzer::PEAnalyzer(const PEClassifier *classifier, DisassemblerAPI *disassembler): Analyzer(disassembler), m_classifier(classifier)
13 {
14     ADD_WNDPROC_API(4, "DialogBoxA");
15     ADD_WNDPROC_API(4, "DialogBoxW");
16     ADD_WNDPROC_API(4, "DialogBoxParamA");
17     ADD_WNDPROC_API(4, "DialogBoxParamW");
18     ADD_WNDPROC_API(4, "CreateDialogParamA");
19     ADD_WNDPROC_API(4, "CreateDialogParamW");
20     ADD_WNDPROC_API(4, "CreateDialogIndirectParamA");
21     ADD_WNDPROC_API(4, "CreateDialogIndirectParamW");
22 }
23 
analyze()24 void PEAnalyzer::analyze()
25 {
26     Analyzer::analyze();
27 
28     if(!m_classifier->isClassified() || m_classifier->checkVisualStudio())
29         this->findCRTWinMain();
30 
31     if(m_classifier->checkVisualStudio())
32     {
33         this->findAllWndProc();
34         REDasm::log("Searching MSVC RTTI...");
35 
36         if(m_classifier->bits() == 64)
37             RTTI::RTTIMsvc<u64>(m_disassembler).search();
38         else
39             RTTI::RTTIMsvc<u32>(m_disassembler).search();
40 
41         return;
42     }
43 
44     this->findAllWndProc();
45 }
46 
getImport(const std::string & library,const std::string & api)47 Symbol* PEAnalyzer::getImport(const std::string &library, const std::string &api)
48 {
49     Symbol* symbol = m_disassembler->document()->symbol(IMPORT_TRAMPOLINE(library, api));
50 
51     if(!symbol)
52         symbol = m_disassembler->document()->symbol(IMPORT_NAME(library, api));
53 
54     return symbol;
55 }
56 
getAPIReferences(const std::string & library,const std::string & api)57 ReferenceVector PEAnalyzer::getAPIReferences(const std::string &library, const std::string &api)
58 {
59     Symbol* symbol = this->getImport(library, api);
60 
61     if(!symbol)
62         return ReferenceVector();
63 
64     return m_disassembler->getReferences(symbol->address);
65 }
66 
findAllWndProc()67 void PEAnalyzer::findAllWndProc()
68 {
69     for(auto it = m_wndprocapi.begin(); it != m_wndprocapi.end(); it++)
70     {
71         ReferenceVector refs = this->getAPIReferences("user32.dll", it->second);
72 
73         for(address_t ref : refs)
74             this->findWndProc(ref, it->first);
75     }
76 }
77 
findWndProc(address_t address,size_t argidx)78 void PEAnalyzer::findWndProc(address_t address, size_t argidx)
79 {
80     auto it = m_document->instructionItem(address);
81 
82     if(it == m_document->end())
83         return;
84 
85     size_t arg = 0;
86     it--; // Skip call
87 
88     while(arg < argidx)
89     {
90         const InstructionPtr& instruction = m_document->instruction((*it)->address);
91 
92         if(!instruction)
93             break;
94 
95         if(instruction->is(InstructionType::Push))
96         {
97             arg++;
98 
99             if(arg == argidx)
100             {
101                 const Operand* op = instruction->op(0);
102                 Segment* segment = m_document->segment(op->u_value);
103 
104                 if(segment && segment->is(SegmentType::Code))
105                 {
106                     m_document->lockFunction(op->u_value, "DlgProc_" + REDasm::hex(op->u_value));
107                     m_disassembler->disassemble(op->u_value);
108                 }
109             }
110         }
111 
112         if((arg == argidx) || (it == m_document->begin()) || instruction->is(InstructionType::Stop))
113             break;
114 
115         it--;
116     }
117 }
118 
findCRTWinMain()119 void PEAnalyzer::findCRTWinMain()
120 {
121     InstructionPtr instruction = m_document->entryInstruction(); // Look for call
122 
123     if(!instruction || !instruction->is(InstructionType::Call))
124         return;
125 
126     Symbol* symbol = m_document->symbol(PE_SECURITY_COOKIE_SYMBOL);
127 
128     if(!symbol)
129         return;
130 
131     auto target = m_disassembler->getTarget(instruction->address);
132 
133     if(!target.valid)
134         return;
135 
136     bool found = false;
137     ReferenceVector refs = m_disassembler->getReferences(symbol->address);
138 
139     for(address_t ref : refs)
140     {
141         const ListingItem* scfuncitem = m_document->functionStart(ref);
142 
143         if(!scfuncitem || ((target != scfuncitem->address)))
144             continue;
145 
146         m_document->lock(scfuncitem->address, "__security_init_cookie");
147         found = true;
148         break;
149     }
150 
151     if(!found || !m_document->advance(instruction) || !instruction->is(InstructionType::Jump))
152         return;
153 
154     m_document->lock(target, "__mainCRTStartup", SymbolType::Function);
155     m_document->setDocumentEntry(target);
156 }
157 
158 }
159