1
0
Fork 0

UInt64 test

This commit is contained in:
tr4ceflow 2014-08-25 22:01:47 +02:00
parent 3f697969f0
commit c38375c1ce
11 changed files with 217 additions and 140 deletions

View File

@ -20,12 +20,10 @@ namespace fa
AnalysisRunner::AnalysisRunner(const duint addrOEP,const duint BaseAddress,const duint Size) : OEP(addrOEP), baseAddress(BaseAddress), codeSize(Size)
{
// we start at the original entry point
disasmRoot.insert(addrOEP);
disasmRoot.insert(std::make_pair<UInt64,UInt64>((duint)addrOEP,(duint)addrOEP));
codeWasCopied = initialise();
if(codeWasCopied){
Grph = new FlowGraph;
Node_t *cipNode = new Node_t(OEP);
Grph->insertNode(cipNode);
}
}
@ -64,35 +62,56 @@ namespace fa
}
bool AnalysisRunner::disasmChilds(duint rootAddress)
bool AnalysisRunner::disasmChilds(const UInt64 currentAddress,UInt64 parentAddress)
{
parentAddress = currentAddress;
// Dear contributors (unless you are Chuck Norris):
//
// if you think about 'optimizing' or 'debugging' this methods and then
// realize what a terrible mistake that was, please pray that this function will
// not fail and increment the following counter as a warning to the next guy:
//
// total_hours_wasted_here = 3
dprintf("-----------------------------------------------------------------------------\n");
dprintf("processing subtree starting in node at address "fhex" as child of "fhex"\n", currentAddress,parentAddress);
// this function will run until an unconditional branching (JMP,RET) or unkown OpCode
if (contains(instructionBuffer,(UInt64)rootAddress))
if (contains(instructionBuffer,(UInt64)currentAddress))
{
// we already were here -->stop!
return true;
}
// is there code?
if((base() > currentAddress) && (base() + size() <= currentAddress)){
return true;
}
DISASM disasm;
memset(&disasm, 0, sizeof(disasm));
#ifdef _WIN64
disasm.Archi = 64;
#endif
// indent pointer relative to current virtual address
disasm.EIP = (UIntPtr)codeBuffer + (rootAddress - baseAddress);
disasm.VirtualAddr = (UInt64)rootAddress;
disasm.EIP = (UIntPtr)codeBuffer + (currentAddress - baseAddress);
disasm.VirtualAddr = (UInt64)currentAddress;
dprintf("loop end test: \n");
dprintf(" va "fhex"\n",disasm.VirtualAddr);
dprintf(" base "fhex"\n",baseAddress);
dprintf(" diff "fhex"\n",(UInt64)(disasm.VirtualAddr- baseAddress));
// while there is code in the buffer
while(disasm.VirtualAddr - baseAddress < codeSize)
{
// disassemble instruction
int instrLength = Disasm(&disasm);
const int instrLength = Disasm(&disasm);
// everything ok?
if(instrLength != UNKNOWN_OPCODE)
{
// create a new structure
Instruction_t instr(&disasm, instrLength);
// cache instruction
const Instruction_t instr(&disasm, instrLength);
//dprintf("analyse %s at "fhex" \n", disasm.CompleteInstr,currentAddress);
// cache instruction, we will later look at it
instructionBuffer.insert(std::pair<UInt64, Instruction_t>(disasm.VirtualAddr, instr));
// handle all kind of branching (cond. jumps, uncond. jumps, ret, unkown OpCode, calls)
@ -107,16 +126,18 @@ namespace fa
// end of a function
// --> start was probably "rootAddress"
// --> edge from current VA to rootAddress
endNode = new Node_t(instruction_t(rootAddress));
endNode = new Node_t(parentAddress);
Edge_t *e = new Edge_t(startNode,endNode,fa::RET);
Grph->insertEdge(e);
//dprintf("try to insert edge from "fhex" to "fhex" \n", e->start->vaddr, e->end->vaddr);
dprintf("--> try to insert ret-edge from "fhex" to "fhex" \n", disasm.VirtualAddr, (UInt64) parentAddress);
//###Grph->insertEdge(e);
// no need to disassemble more
// "rootAddress" is from "call <rootAddress>"
// "rootAddress" is *only sometimes* from "call <rootAddress>"
return true;
}else{
// this is a "call","jmp","ret","jne","jnz","jz",...
// this is a "call","jmp","jne","jnz","jz",...
// were we are going to?
endNode = new Node_t(instruction_t(rootAddress));
//### endNode = new Node_t(instruction_t(disasm.Instruction.AddrValue));
// determine the type of flow-control-modification
fa::EdgeType currentEdgeType;
@ -124,8 +145,7 @@ namespace fa
// simply a call
currentEdgeType = fa::CALL;
}else if(BT == JmpType){
// external Jump ?
// TODO: this is currently x86 only!
// external Jump to known api call?
bool extjmp;
#ifndef _WIN64
extjmp =( disasm.Instruction.Opcode == 0xFF);
@ -139,7 +159,7 @@ namespace fa
extjmp = !f.invalid;
}
#endif
if(extjmp){
if(extjmp ){
currentEdgeType = fa::EXTERNJMP;
}else{
currentEdgeType = fa::UNCONDJMP;
@ -150,11 +170,19 @@ namespace fa
}
// create a new edge for this EIP change
Edge_t *edge = new Edge_t(startNode,endNode,currentEdgeType);
Grph->insertEdge(edge);
dprintf("--> try to insert edge from "fhex" to "fhex" \n", disasm.VirtualAddr, (UInt64) disasm.Instruction.AddrValue);
//####Grph->insertEdge(edge);
if(currentEdgeType != fa::EXTERNJMP){
// the target must be disassembled too --> insert on todo-list
disasmRoot.insert(endNode->virtualAddress);
if(currentEdgeType == fa::CALL){
// pass new address for correct resolving function-header addresses
disasmRoot.insert(std::make_pair<UInt64,UInt64>(disasm.Instruction.AddrValue,disasm.VirtualAddr));
}else{
// we are in some functions --> propagate current function start
disasmRoot.insert(std::make_pair<UInt64,UInt64>(disasm.Instruction.AddrValue,parentAddress));
}
dprintf("add todo at "fhex" from "fhex" \n", disasm.Instruction.AddrValue,disasm.VirtualAddr);
}
if( BT == JmpType ){
@ -175,6 +203,11 @@ namespace fa
// we are allowed to analyze the next instruction
disasm.EIP += instrLength;
disasm.VirtualAddr += instrLength;
dprintf("loop end test: \n");
dprintf(" va "fhex"\n",disasm.VirtualAddr);
dprintf(" base "fhex"\n",baseAddress);
dprintf(" diff "fhex"\n",(UInt64)(disasm.VirtualAddr- baseAddress));
}
return true;
@ -182,22 +215,33 @@ namespace fa
void AnalysisRunner::buildGraph()
{
int i=15;
// execute todo list
while(disasmRoot.size() != 0){
// get any address
UInt64 addr = *(disasmRoot.begin());
std::pair<UInt64,UInt64> addr = *(disasmRoot.begin());
// does the address makes sense?
if( (addr.first >= baseAddress) && (addr.first < baseAddress + codeSize) ){
// did we already analyzed that address?
if(!contains(instructionBuffer,addr)){
if(!contains(instructionBuffer,addr.first)){
// analyze until branching
disasmChilds(addr);
disasmChilds(addr.first,addr.second);
}
}
// delete it from todo list
disasmRoot.erase(disasmRoot.find(addr));
if(i==0)
return;
i--;
}
// we do not need the buffer anymore
delete codeBuffer;
}
std::map<UInt64, Instruction_t>::const_iterator AnalysisRunner::instruction(UInt64 addr) const
{
return instructionBuffer.find(addr);
@ -206,7 +250,7 @@ namespace fa
{
return instructionBuffer.end();
}
duint AnalysisRunner::base() const
UInt64 AnalysisRunner::base() const
{
return baseAddress;
}

View File

@ -7,6 +7,8 @@
namespace fa
{
// BeaEngine uses "UInt64" as default size type. We will do the same here in contrast to "duint"
class StackEmulator;
class RegisterEmulator;
class FunctionInfo;
@ -14,13 +16,13 @@ namespace fa
class AnalysisRunner
{
// we will place all VA here that should be a start address for disassembling
std::set<UInt64> disasmRoot;
std::set< std::pair<UInt64,UInt64> > disasmRoot;
// all known disassemling should be cached
std::map<UInt64, Instruction_t> instructionBuffer;
// baseaddress for current thread
duint baseAddress;
UInt64 baseAddress;
// size of code for security while disassembling
duint codeSize;
UInt64 codeSize;
// copy of all instructions bytes
unsigned char* codeBuffer;
// temporal value of EIP
@ -44,7 +46,7 @@ protected:
private:
void buildGraph();
void emulateInstructions();
bool disasmChilds(duint addr);
bool disasmChilds(const UInt64 addr,UInt64 paddr);
public:
@ -56,7 +58,7 @@ public:
Instruction_t instruction_t(UInt64 va) const;
std::map<UInt64, Instruction_t>::const_iterator lastInstruction() const;
duint base() const;
UInt64 base() const;
UInt64 oep() const;
duint size() const;
FlowGraph* graph() const;

View File

@ -8,6 +8,7 @@
#include "FlowGraph.h"
#include "AnalysisRunner.h"
#include "StackEmulator.h"
#include "FunctionInfo.h"
namespace fa
{
@ -30,7 +31,7 @@ namespace fa
#endif
if(hasLabel){
FunctionInfo_t f = Analysis->functioninfo()->find(labelText);
fa::FunctionInfo_t f = Analysis->functioninfo()->find(labelText);
if(!f.invalid)
{
// yeah we know everything about the dll-call!
@ -40,7 +41,7 @@ namespace fa
#ifndef _WIN64
// set comments for the arguments
for(auto i = 0; i < f.Arguments.size(); i++)
for(size_t i = 0; i < f.Arguments.size(); i++)
{
std::string ArgComment = f.arg(i).Type + " " + f.arg(i).Name;
uint commentAddr = stack->lastAccessAtOffset(f.Arguments.size() - i - 1);

View File

@ -1,6 +1,7 @@
#include "FlowGraph.h"
#include "Node_t.h"
#include "Edge_t.h"
#include "../console.h"
namespace fa{
@ -11,27 +12,37 @@ namespace fa{
}
std::pair<std::set<Node_t*>::iterator,bool> FlowGraph::insertNode( Node_t* node )
bool FlowGraph::insertNode( Node_t* node )
{
return nodes.insert(node);
if (!contains(nodes,(UInt64)node->vaddr))
{
return (nodes.insert(std::make_pair<UInt64,Node_t*>(node->vaddr,node))).second;
}
return true;
}
std::pair<std::set<Edge_t*>::iterator,bool> FlowGraph::insertEdge( Edge_t* edge )
bool FlowGraph::insertEdge( Edge_t* edge )
{
// until here a node just contains an address!
// we search for these address to get most updated information (like incoming edges)
std::pair<std::set<Node_t*>::iterator,bool> start = insertNode(edge->start);
std::pair<std::set<Node_t*>::iterator,bool> end = insertNode(edge->end);
// insert current edge into these nodes
(*start.first)->outEdge.insert(edge);
(*end.first)->inEdges.insert(edge);
dprintf("try to insert edge from "fhex" to "fhex" \n", edge->start->vaddr, edge->end->vaddr);
return true;
insertNode(edge->start);
std::map<UInt64,Node_t*>::iterator it = nodes.find(edge->start->vaddr);
it->second->outEdge = edge;
// update edge
edge->start = (*start.first);
edge->end = (*end.first);
insertNode(edge->end);
std::map<UInt64,Node_t*>::iterator it2 = nodes.find(edge->end->vaddr);
it2->second->inEdges.insert(edge);
return edges.insert(edge);
edge->start = (it->second);
edge->end = (it2->second);
bool ans = edges.insert(std::make_pair<UInt64,Edge_t*>(edge->start->vaddr,edge)).second;
std::map<UInt64,Edge_t*>::iterator e = edges.find(edge->start->vaddr);
return ans;
}
@ -39,32 +50,32 @@ namespace fa{
void FlowGraph::clean()
{
// first delete all edges whoses aks for it
std::set<Edge_t*>::iterator e = edges.begin();
std::map<UInt64,Edge_t*>::iterator e = edges.begin();
while(e != edges.end()) {
std::set<Edge_t*>::iterator current = e++;
if((*current)->askForRemove){
delete *current;
std::map<UInt64,Edge_t*>::iterator current = e++;
if((*current->second).askForRemove){
delete current->second;
edges.erase(current);
}
}
// find and delete isolated nodes, i.e. nodes without incoming and outgoing edges
std::set<Node_t*>::iterator n = nodes.begin();
std::map<UInt64,Node_t*>::iterator n = nodes.begin();
while(n != nodes.end()) {
std::set<Node_t*>::iterator current = n++;
if( (!(*current)->outEdge) && ((*current)->inEdges.size()==0) ){
delete *current;
std::map<UInt64,Node_t*>::iterator current = n++;
if( (!(*current->second).outEdge) && ((*current->second).inEdges.size()==0) ){
delete current->second;
nodes.erase(current);
}
}
}
bool FlowGraph::find(const UInt64 va , Node_t *node)
{
// try to find a node
std::set<Node_t*>::iterator it = nodes.find(Node_t(va));
node = *it;
std::map<UInt64,Node_t*>::iterator it = nodes.find(va);
Node_t* n = it->second;
node = n;
return (it != nodes.end());
}

View File

@ -1,30 +1,31 @@
#pragma once
#include <set>
#include "../_global.h"
#include "Node_t.h"
#include "Edge_t.h"
namespace fa{
class Edge_t;
class Node_t;
class FlowGraph
{
// this class represents the program flow including branches likes JMP, JNE, ... , CALL, RET
// all existing edges
std::set<Edge_t*> edges;
std::map<UInt64,Edge_t*> edges;
// all existing nodes
std::set<Node_t*> nodes;
std::map<UInt64,Node_t*> nodes;
public:
FlowGraph(void);
~FlowGraph(void);
void clean();
// insert a new node an returns the existing node if there was already the node
// WARNING: this should only be called from the corresponding edge!!!
std::pair<std::set<Node_t*>::iterator,bool> insertNode(Node_t* node);
bool insertNode(Node_t* node);
// insert a new edge an returns the existing edge if there was already the edge
std::pair<std::set<Edge_t*>::iterator,bool> FlowGraph::insertEdge( Edge_t* edge );
bool FlowGraph::insertEdge( Edge_t* edge );
bool find(const UInt64 va , Node_t *node);
bool find(const UInt64 va, Node_t *node);
};
}

View File

@ -14,7 +14,7 @@
namespace fa
{
enum EdgeType{RET,CALL,CONDJMP,UNCONDJMP,EXTERNJMP,INF,UNKOWN};
enum EdgeType{RET,CALL,EXTERNCALL,CONDJMP,UNCONDJMP,EXTERNJMP,INF,UNKOWN};
@ -33,6 +33,7 @@ namespace fa
Instruction_t()
{
BeaStruct = DISASM();
Length = UNKNOWN_OPCODE;
}
} Instruction_t;
@ -72,14 +73,15 @@ namespace fa
Arguments = args;
invalid = false;
}
// !! suppresses the warning (ugly solution)
bool operator==(const FunctionInfo_t & rhs) const
{
return static_cast<bool>((_strcmpi(Name.c_str(), rhs.Name.c_str()) < 0));
return static_cast<bool>(!!(_strcmpi(Name.c_str(), rhs.Name.c_str()) < 0));
}
// !! suppresses the warning (ugly solution)
bool operator<(const FunctionInfo_t & rhs) const
{
return static_cast<bool>(_strcmpi(Name.c_str(), rhs.Name.c_str()));
return static_cast<bool>(!!_strcmpi(Name.c_str(), rhs.Name.c_str()));
}
ArgumentInfo_t arg(int i)

View File

@ -9,10 +9,18 @@ namespace fa
Node_t::Node_t(Instruction_t t){
outEdge = NULL;
instruction = t;
vaddr = t.BeaStruct.VirtualAddr;
}
Node_t::Node_t(){
outEdge = NULL;
instruction = Instruction_t();
vaddr = 0;
}
Node_t::Node_t(UInt64 va){
outEdge = NULL;
instruction = Instruction_t();
instruction.BeaStruct.VirtualAddr = va;
vaddr = va;
}
Node_t::~Node_t(){
@ -31,17 +39,14 @@ namespace fa
// nodes are unique with respect to their virtual address
bool Node_t::operator==(const Node_t & rhs) const
{
if(instruction.Length != UNKNOWN_OPCODE)
return static_cast<bool>(instruction.BeaStruct.VirtualAddr == rhs.instruction.BeaStruct.VirtualAddr);
else
return false;
return static_cast<bool>(vaddr == rhs.vaddr);
}
bool Node_t::operator<(const Node_t & rhs) const
{
if(instruction.Length != UNKNOWN_OPCODE)
return static_cast<bool>(instruction.BeaStruct.VirtualAddr < rhs.instruction.BeaStruct.VirtualAddr);
else
return false;
return static_cast<bool>(vaddr < rhs.vaddr);
}

View File

@ -11,8 +11,10 @@ namespace fa
Edge_t* outEdge; // all outgoing edges
std::set<Edge_t*> inEdges; // all incoming edges
Instruction_t instruction;
UInt64 vaddr;
Node_t(Instruction_t t);
Node_t(UInt64 t);
Node_t();
~Node_t();
void remove();

View File

@ -11,7 +11,7 @@
#include "simplescript.h"
#include "symbolinfo.h"
#include "Analysis/AnalysisRunner.h"
#include "Analysis/ApiDB.h"
static bool bScyllaLoaded = false;
@ -999,28 +999,25 @@ CMDRESULT cbDebugBcDll(int argc, char* argv[])
}
CMDRESULT cbDebugAnalyse(int argc, char* argv[])
{
dputs("start analysis");
uint addr = GetContextData(UE_CIP);
if(argc > 1 and !valfromstring(argv[1], &addr))
{
dprintf("invalid address \"%s\"!\n", argv[1]);
return STATUS_ERROR;
}
dprintf("valid cip "fhex"!\n", addr);
dputs("init analysis");
uint cipAddr = GetContextData(UE_CIP);
uint size;
uint base = memfindbaseaddr(addr, &size);
uint base = memfindbaseaddr(cipAddr, &size);
if(!base)
{
dprintf("invalid address "fhex"!\n", addr);
dprintf("invalid address "fhex"!\n", base);
return STATUS_ERROR;
}
dprintf("valid base "fhex"!\n", base);
dprintf("valid size "fhex"!\n", size);
tr4ce::ApiDB* db = new tr4ce::ApiDB();
tr4ce::AnalysisRunner AR(base, size);
AR.setFunctionInformation(db);
dprintf("start analysis, assuming oep="fhex", baseaddr="fhex", size="fhex"!\n", cipAddr,base,size);
// tr4ce::ApiDB* db = new tr4ce::ApiDB();
fa::AnalysisRunner AR(cipAddr,base, size);
AR.start();
// AR.setFunctionInformation(db);
// AR.start();
//GuiAnalyseCode(base, size);

View File

@ -13,12 +13,13 @@
<ItemGroup>
<ClCompile Include="addrinfo.cpp" />
<ClCompile Include="Analysis\AnalysisRunner.cpp" />
<ClCompile Include="Analysis\ApiDB.cpp" />
<ClCompile Include="Analysis\BeaInterpreter.cpp" />
<ClCompile Include="Analysis\FunctionDetector.cpp" />
<ClCompile Include="Analysis\ICommand.cpp" />
<ClCompile Include="Analysis\IntermodularCallsX64.cpp" />
<ClCompile Include="Analysis\IntermodularCallsX86.cpp" />
<ClCompile Include="Analysis\ClientApiResolver.cpp" />
<ClCompile Include="Analysis\ClientFunctionFinder.cpp" />
<ClCompile Include="Analysis\ClientInterface.cpp" />
<ClCompile Include="Analysis\Edge_t.cpp" />
<ClCompile Include="Analysis\FlowGraph.cpp" />
<ClCompile Include="Analysis\FunctionInfo.cpp" />
<ClCompile Include="Analysis\Node_t.cpp" />
<ClCompile Include="Analysis\RegisterEmulator.cpp" />
<ClCompile Include="Analysis\StackEmulator.cpp" />
<ClCompile Include="argument.cpp" />
@ -55,12 +56,14 @@
<ItemGroup>
<ClInclude Include="addrinfo.h" />
<ClInclude Include="Analysis\AnalysisRunner.h" />
<ClInclude Include="Analysis\ApiDB.h" />
<ClInclude Include="Analysis\BeaInterpreter.h" />
<ClInclude Include="Analysis\FunctionDetector.h" />
<ClInclude Include="Analysis\ICommand.h" />
<ClInclude Include="Analysis\IntermodularCalls.h" />
<ClInclude Include="Analysis\ClientApiResolver.h" />
<ClInclude Include="Analysis\ClientFunctionFinder.h" />
<ClInclude Include="Analysis\ClientInterface.h" />
<ClInclude Include="Analysis\Edge_t.h" />
<ClInclude Include="Analysis\FlowGraph.h" />
<ClInclude Include="Analysis\FunctionInfo.h" />
<ClInclude Include="Analysis\Meta.h" />
<ClInclude Include="Analysis\Node_t.h" />
<ClInclude Include="Analysis\RegisterEmulator.h" />
<ClInclude Include="Analysis\StackEmulator.h" />
<ClInclude Include="argument.h" />

View File

@ -34,12 +34,12 @@
<Filter Include="Header Files\lz4">
<UniqueIdentifier>{6a8d58f0-1417-4bff-aecd-0f9f5e0641f9}</UniqueIdentifier>
</Filter>
<Filter Include="Analysis">
<UniqueIdentifier>{70e48ca5-7813-4da6-95c8-3717ace25093}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Analysis">
<UniqueIdentifier>{68e04c31-9f66-4c9a-ae1d-54b2f6cf2d1c}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\fa">
<UniqueIdentifier>{70e48ca5-7813-4da6-95c8-3717ace25093}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="_exports.cpp">
@ -135,32 +135,35 @@
<ClCompile Include="debugger_commands.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Analysis\Node_t.cpp">
<Filter>Header Files\fa</Filter>
</ClCompile>
<ClCompile Include="Analysis\Edge_t.cpp">
<Filter>Header Files\fa</Filter>
</ClCompile>
<ClCompile Include="Analysis\AnalysisRunner.cpp">
<Filter>Source Files\Analysis</Filter>
<Filter>Header Files\fa</Filter>
</ClCompile>
<ClCompile Include="Analysis\StackEmulator.cpp">
<Filter>Source Files\Analysis</Filter>
<Filter>Header Files\fa</Filter>
</ClCompile>
<ClCompile Include="Analysis\FlowGraph.cpp">
<Filter>Header Files\fa</Filter>
</ClCompile>
<ClCompile Include="Analysis\RegisterEmulator.cpp">
<Filter>Source Files\Analysis</Filter>
<Filter>Header Files\fa</Filter>
</ClCompile>
<ClCompile Include="Analysis\IntermodularCallsX64.cpp">
<Filter>Source Files\Analysis</Filter>
<ClCompile Include="Analysis\ClientApiResolver.cpp">
<Filter>Header Files\fa</Filter>
</ClCompile>
<ClCompile Include="Analysis\IntermodularCallsX86.cpp">
<Filter>Source Files\Analysis</Filter>
<ClCompile Include="Analysis\ClientInterface.cpp">
<Filter>Header Files\fa</Filter>
</ClCompile>
<ClCompile Include="Analysis\ICommand.cpp">
<Filter>Source Files\Analysis</Filter>
<ClCompile Include="Analysis\FunctionInfo.cpp">
<Filter>Header Files\fa</Filter>
</ClCompile>
<ClCompile Include="Analysis\ApiDB.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="Analysis\FunctionDetector.cpp">
<Filter>Source Files\Analysis</Filter>
</ClCompile>
<ClCompile Include="Analysis\BeaInterpreter.cpp">
<Filter>Source Files\Analysis</Filter>
<ClCompile Include="Analysis\ClientFunctionFinder.cpp">
<Filter>Header Files\fa</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
@ -308,32 +311,38 @@
<ClInclude Include="dynamicmem.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Analysis\Meta.h">
<Filter>Analysis</Filter>
</ClInclude>
<ClInclude Include="Analysis\AnalysisRunner.h">
<Filter>Analysis</Filter>
<Filter>Header Files\fa</Filter>
</ClInclude>
<ClInclude Include="Analysis\StackEmulator.h">
<Filter>Analysis</Filter>
<Filter>Header Files\fa</Filter>
</ClInclude>
<ClInclude Include="Analysis\RegisterEmulator.h">
<Filter>Analysis</Filter>
<Filter>Header Files\fa</Filter>
</ClInclude>
<ClInclude Include="Analysis\IntermodularCalls.h">
<Filter>Analysis</Filter>
<ClInclude Include="Analysis\FlowGraph.h">
<Filter>Header Files\fa</Filter>
</ClInclude>
<ClInclude Include="Analysis\ICommand.h">
<Filter>Analysis</Filter>
<ClInclude Include="Analysis\Meta.h">
<Filter>Header Files\fa</Filter>
</ClInclude>
<ClInclude Include="Analysis\ApiDB.h">
<Filter>Analysis</Filter>
<ClInclude Include="Analysis\Node_t.h">
<Filter>Header Files\fa</Filter>
</ClInclude>
<ClInclude Include="Analysis\FunctionDetector.h">
<Filter>Analysis</Filter>
<ClInclude Include="Analysis\Edge_t.h">
<Filter>Header Files\fa</Filter>
</ClInclude>
<ClInclude Include="Analysis\BeaInterpreter.h">
<Filter>Analysis</Filter>
<ClInclude Include="Analysis\ClientApiResolver.h">
<Filter>Header Files\fa</Filter>
</ClInclude>
<ClInclude Include="Analysis\ClientInterface.h">
<Filter>Header Files\fa</Filter>
</ClInclude>
<ClInclude Include="Analysis\FunctionInfo.h">
<Filter>Header Files\fa</Filter>
</ClInclude>
<ClInclude Include="Analysis\ClientFunctionFinder.h">
<Filter>Header Files\fa</Filter>
</ClInclude>
</ItemGroup>
</Project>