アマチュアおよびバックエンジニアリング。 パート2:ワイヤフレーム





前回 、リバースエンジニアリングの関係の始まりについて説明しました 。 もう少し時間が経ち、今ではある程度、私の研究の結果です。



.dllライブラリと.pdbデータベースからソースを復元しようとしています。 IDAを使用すると確かに結果が得られますが、満足できるものではありません。 たぶん私はただ勤勉ではありません。 したがって、私は反対に始めました-ライブラリプロジェクトのフレームワークの復元から。 私は.pdbデータベースを持っているので、非常にうまくできます。 理論的に。 理論的には、データベースはソースではなく前処理されたファイルから情報を記録するためです。 だから、あなたは取り組む必要があります。



充填



理論から話を始めましょう。 構造的には、.pdb-baseは相互接続された一連の文字(任意の変数、構造、関数、列挙、型、これらはすべて文字)です。 シンボルはタイプごとに分けられており、タイプに応じて異なるプロパティを設定できます。 プロパティを読み取ることで、構造、関数、オーバーライド、列挙、定数の説明を取得できます。これには、これらすべての関係、ファイルの名前、関数が配置されている.objモジュールなどが含まれます。 シンボルへのアクセスについては、DIA SDK(デバッグインターフェイスアクセス)があり、十分に文書化されており、その処理はそれほど難しくありません。 唯一の「問題」は、DIAがそのまま使用できるのはC / C ++のみであり、.Netで作業する場合は、インターフェイスを.Net .dllに移動して作業する必要があることですが、それは別の話です。 完成したモジュールを簡単に見つけることができます。 個人的には、Dia2Lib.dllを見つけることで2番目のオプションを選択しましたが、いくつかの関数が間違って翻訳されました(配列の代わりに、いくつかの関数のパラメーターに単純な変数を挿入しました)。



おそらく、.pdbデータベースからコードを生成するための既成のソリューションがありますが、見つかりませんでした。 そして今、私は自分で書いています。 私はC#で記述しますが、ファイルの操作の利便性は犠牲になりますが、メモリの問題は少なくなります。 最初に、キャラクターを記述するためのクラスが必要でした。 標準的なもの(Dia2Libのもの)は少し不快です。 より正確には、3自由度でデータを回転させたい場合、彼らは単にそれを我慢できません。

文字データを処理するためのクラス
class Member { public string name; public int offcet; //  public ulong length; //    public string type; //  ,  , ,   .. public string access; //  public uint id; //    } class BaseClass { public string type; public int offcet; //   public ulong length; public uint id; } class Function { public string name; public string type; public string access; public string filename; // ,    public uint id; } class Typedef { public string name; public string type; public uint id; } class Enum { public string name; public uint id; public SubEnum[] values; } class SubEnum { public string name; public dynamic value; public uint id; } class VTable { public ulong count; //  public string type; public uint id; } class SubStructure { public string name; public uint id; } class Structure { public string name; public uint id; public Member[] members; public BaseClass[] baseclass; public Function[] functions; public Typedef[] typedefs; public Enum[] enums; public VTable[] vtables; public SubStructure[] substructures; }
      
      





これらの構造体の配列に文字の通常の列挙を入力し、フレームワークの基礎を取得できます。 問題が始まった後。 最初の問題は、すでに述べたように、データベースには前処理されたファイルのすべての構造が記録されます。 たとえば次のように:

最初の例はあまり必要な構造ではありません
 struct /*id:2*/ _iobuf { /*off 0x00000000 size:0004 id:5*/ public: char * _ptr; /*off 0x00000004 size:0004 id:8*/ public: signed int _cnt; /*off 0x00000008 size:0004 id:5*/ public: char * _base; /*off 0x00000012 size:0004 id:8*/ public: signed int _flag; /*off 0x00000016 size:0004 id:8*/ public: signed int _file; /*off 0x00000020 size:0004 id:8*/ public: signed int _charbuf; /*off 0x00000024 size:0004 id:8*/ public: signed int _bufsiz; /*off 0x00000028 size:0004 id:5*/ public: char * _tmpfname; };
      
      





標準ライブラリの構造を使用できる人はほとんどいません。 しかし、それでも何らかの方法で追跡できる場合は、さらに悪い例があります。

2番目の例はあまり必要な構造ではありません
 struct /*id:24371*/ std::allocator<std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node>:/*0x0 id:24351*/ std::_Allocator_base<std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node> { // /*id:24362*/ public: __thiscall const std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node * address (const std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node &); // /*id:24364*/ public: __thiscall std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node * address (std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node &); // /*id:24367*/ public: __thiscall void allocator<std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node> (const std::allocator<std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node> &); // /*id:24372*/ public: __thiscall void allocator<std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node> (); //:d:\program files\microsoft visual studio .net 2003\vc7\include\xmemory /*id:24374 */public: void __thiscall std::allocator<struct std::_Tree_nod<class std::_Tmap_traits<int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<int>,class std::allocator<struct std::pair<int const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >,0> >::_Node>::deallocate(struct std::_Tree_nod<class std::_Tmap_traits<int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<int>,class std::allocator<struct std::pair<int const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >,0> >::_Node *,unsigned int); // /*id:24376*/ public: __thiscall std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node * allocate (unsigned int ,const void *); //:d:\program files\microsoft visual studio .net 2003\vc7\include\xmemory /*id:24378 */public: struct std::_Tree_nod<class std::_Tmap_traits<int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<int>,class std::allocator<struct std::pair<int const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >,0> >::_Node * __thiscall std::allocator<struct std::_Tree_nod<class std::_Tmap_traits<int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<int>,class std::allocator<struct std::pair<int const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >,0> >::_Node>::allocate(unsigned int); // /*id:24380*/ public: __thiscall void construct (std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node *,const std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node &); //:d:\program files\microsoft visual studio .net 2003\vc7\include\xmemory /*id:24384 */public: void __thiscall std::allocator<struct std::_Tree_nod<class std::_Tmap_traits<int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<int>,class std::allocator<struct std::pair<int const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >,0> >::_Node>::destroy(struct std::_Tree_nod<class std::_Tmap_traits<int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<int>,class std::allocator<struct std::pair<int const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >,0> >::_Node *); // /*id:24386*/ public: __thiscall unsigned int max_size (); structure /*id:24353*/ value_type; typedef /*id:24352*/std::_Allocator_base<std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node> _Mybase; typedef /*id:24354*/std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node * pointer; typedef /*id:24355*/std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node & reference; typedef /*id:24357*/const std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node * const_pointer; typedef /*id:24359*/const std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::less<int>,std::allocator<std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node & const_reference; typedef /*id:24360*/unsigned int size_type; typedef /*id:24361*/signed int difference_type; };
      
      





また、標準のテンプレート構造でフィルターを作成しても、翻訳中に展開または変更される多くの言語機能が残ります。 例として、カスタムテンプレートに名前を付けることができます。

テンプレートスイープの例
 struct /*id:16851*/ S_BVECTOR<D3DXVECTOR2> { /*off 0x00000000 size:0016 id:9357*/ private: std::vector<D3DXVECTOR2,std::allocator<D3DXVECTOR2> > m_VECPath; /*off 0x00000016 size:0004 id:8*/ private: signed int m_nCount; /*off 0x00000020 size:0004 id:8*/ private: signed int m_nPos; /*id:9360 */public: __thiscall S_BVECTOR<struct D3DXVECTOR2>::S_BVECTOR<struct D3DXVECTOR2>(class S_BVECTOR<struct D3DXVECTOR2> const &); /*id:9362 */public: __thiscall S_BVECTOR<struct D3DXVECTOR2>::S_BVECTOR<struct D3DXVECTOR2>(void); /*id:9364 */public: void __thiscall S_BVECTOR<struct D3DXVECTOR2>::resize(unsigned short); /*id:9366*/ public: __thiscall void addsize (unsigned short ); /*id:9368 */public: void __thiscall S_BVECTOR<struct D3DXVECTOR2>::setsize(unsigned short); /*id:9369*/ public: __thiscall void setsizeNew (unsigned short ); /*id:9370 */public: void __thiscall S_BVECTOR<struct D3DXVECTOR2>::clear(void); /*id:9371 */public: void __thiscall S_BVECTOR<struct D3DXVECTOR2>::push_back(struct D3DXVECTOR2 &); /*id:9373*/ public: __thiscall void pop_front (); /*id:9374*/ public: __thiscall void pop_back (); /*id:9375 */public: int __thiscall S_BVECTOR<struct D3DXVECTOR2>::size(void); /*id:9377 */public: bool __thiscall S_BVECTOR<struct D3DXVECTOR2>::empty(void); /*id:9379*/ public: __thiscall D3DXVECTOR2 * front (); /*id:9381*/ public: __thiscall D3DXVECTOR2 * next (); /*id:9382*/ public: __thiscall D3DXVECTOR2 * end (); /*id:9383 */public: struct D3DXVECTOR2 * __thiscall S_BVECTOR<struct D3DXVECTOR2>::operator[](int); /*id:9385*/ public: __thiscall void remove (signed int ); /*id:9387 */public: __thiscall S_BVECTOR<struct D3DXVECTOR2>::~S_BVECTOR<struct D3DXVECTOR2>(void); /*id:9388*/ public: __thiscall void * __vecDelDtor (unsigned int ); };
      
      





もちろん、すべてを簡単に元の形式に戻すことができます。 ただし、手動処理が必要な状況は非常に多くなります。 たとえば、使用したいライブラリの場合、2673構造がデータベースに書き込まれます。 これらのうち、実際に必要なのは約250のみで、残りはstdテンプレートスキャンおよびその他の「標準」のものです。 すべてが問題なく進むことを望むだけです。 さて、構造体に空白があると仮定します。 次に、それらをファイルに書き込む必要があります。



世代



最初に、録音用のファイル自体が必要です。 ちょっとした理論。 コンパイル時に、プリプロセッサの後のコードを含む各ソースは、コンパイラを使用してマシンコードに変換されます。 各ソースコードから、コンパイラに応じて.objファイルまたは.oファイルが取得されます。 DIA SDKを使用すると、各.objモジュールからすべてのファイルのリストを取得できます(要するに、#includeに含まれているもののリスト全体)。 ファイルのリストを取得する方法は、以前の記事で説明されていました(説明されているように...一般的にはコードがあります )。 アマチュアの言語で言えば、各.objモジュールから、モジュールが使用されていたソースの名前(それらは同じ名前になります)および接続されたライブラリのリスト(例外がありますが、.cppを除くすべてのファイルが含まれます)を取得できます。 共通の構造を作成し、パーツをリンクしたら、構造の記録を開始できます。



私の知る限り、ソースの形式で構造が存在していたファイルの名前を直接取得することは不可能です。 しかし、構造化メソッドの実装が散在しているファイルを見つけることができます。 したがって、関数メソッドを含むすべてのファイルを単に収集し、それらからヘッダーになるファイルを選択し、そこに説明を記述し、残りのファイルをヘッダーに関連付けることをお勧めします。 しかし、メソッドが置かれているソースの名前を取得すると、それは不快であるか、バグであるか、ファイルエラーが発生している可能性があります。 名前を取得するには、まずRVA(相対仮想アドレス)でソース行のリストを見つける必要があり、次にこの行リストでこれらの行があるファイルを見つけます。 ただし、メソッドに対応する行数がゼロである場合もありますが、ファイル名はまだあります。 そして、通常、間違った名前。 これは通常、コンストラクターの分析に現れます。 たぶん、コンストラクタは単に考慮していません...

コンストラクターの壊れた配置を持つ構造体の例
 //      -   .     -    ,   . //e:\????\kop\project\mindpower\sdk\src\mpfont.cpp //e:\????\kop\project\mindpower\sdk\src\i_effect.cpp //e:\????\kop\project\mindpower\sdk\include\i_effect.h struct /*id:9920*/ CTexList { /*off 0x00000000 size:0002 id:1138*/ public: unsigned short m_wTexCount; /*off 0x00000004 size:0004 id:1778*/ public: float m_fFrameTime; /*off 0x00000008 size:0016 id:9726*/ public: std::vector<std::vector<D3DXVECTOR2,std::allocator<D3DXVECTOR2> >,std::allocator<std::vector<D3DXVECTOR2,std::allocator<D3DXVECTOR2> > > > m_vecTexList; /*off 0x00000024 size:0028 id:98*/ public: std::basic_string<char,std::char_traits<char>,std::allocator<char> > m_vecTexName; /*off 0x00000052 size:0004 id:8384*/ public: IDirect3DTexture8 * m_lpCurTex; /*off 0x00000056 size:0004 id:8130*/ public: MindPower::lwITex * m_pTex; //:e:\????\kop\project\mindpower\sdk\src\mpfont.cpp[0] /*id:9921*/ public: __thiscall void CTexList::CTexList (const CTexList &); //:e:\????\kop\project\mindpower\sdk\src\i_effect.cpp[3] /*id:9927*/ public: __thiscall void CTexList::CTexList (); //:e:\????\kop\project\mindpower\sdk\src\i_effect.cpp[2] /*id:9929*/ public: __thiscall void CTexList::~CTexList (); //:e:\????\kop\project\mindpower\sdk\src\i_effect.cpp[3] /*id:9930*/ public: __thiscall void CTexList::SetTextureName (const std::basic_string<char,std::char_traits<char>,std::allocator<char> > &); //:e:\????\kop\project\mindpower\sdk\src\i_effect.cpp[16] /*id:9932*/ public: __thiscall void CTexList::GetTextureFromModel (CEffectModel *); //:e:\????\kop\project\mindpower\sdk\src\i_effect.cpp[25] /*id:9934*/ public: __thiscall void CTexList::CreateSpliteTexture (signed int ,signed int ); //:e:\????\kop\project\mindpower\sdk\src\i_effect.cpp[16] /*id:9936*/ public: __thiscall void CTexList::GetCurTexture (S_BVECTOR<D3DXVECTOR2> &,unsigned short &,float &,float ); //:e:\????\kop\project\mindpower\sdk\src\i_effect.cpp[2] /*id:9938*/ public: __thiscall void CTexList::Reset (); //:e:\????\kop\project\mindpower\sdk\src\i_effect.cpp[7] /*id:9939*/ public: __thiscall void CTexList::Clear (); //:e:\????\kop\project\mindpower\sdk\src\i_effect.cpp[6] /*id:9940*/ public: __thiscall void CTexList::Remove (); //:e:\????\kop\project\mindpower\sdk\include\i_effect.h[12] /*id:9941*/ public: __thiscall void CTexList::Copy (CTexList *); };
      
      





通常、そして当然のことながら、構造はheader.hとcode.cppの2つのファイルにありますが、他のオプションがあります。 たとえば、構造にはヘッダーのみが含まれているか、コードを含むファイルは拡張子.inlで表されます。または、構造は通常.pdbデータベースに従ってどこにも書き込まれません。 次のアルゴリズムを使用しました。 構造が含まれるファイルのリストにヘッダーがある場合、ヘッダーに構造を書き込み、コードがあればファイルに接続します。 構造を調べて、使用されるすべてのタイプのリストを作成します。 タイプが構造であり、そのファイルのリストがある場合は、この構造のヘッダーを接続します。そうでない場合は、この構造をファイルの先頭に書き込みます。 もう1つの不快な瞬間があります。構造は複製が非常に好きです。 それらの多くが何度も発生する理由がわかりません(実際、次から次へと多くの標準テンプレートがありますが、フィルターを有効にすると、次々に有効になります)。 さらに、そのような構造のプロパティ/メソッドは一致しますが、シリアル番号のみが異なります。 個人的には、構造体の名前の背後にある構造体で配列をソートし、すべての要素を反復処理するときに、現在の名前と前の名前を比較しました。 そしてそれは働いた。



結果



それはすべてうまくいきましたが、もちろん、私たちが望んでいるようではありません。 もちろん、それは多くのファイルを作成し、一般に、私が望むように、元のプロジェクトの構造を表示しましたが、そのような混乱があります...

生成されたファイルの1つはlwitem.hです
 //         #ifndef __MINDPOWER::LWITEM__ #define __MINDPOWER::LWITEM__ #ifndef _MINDPOWER::LWIRESOURCEMGR_ #define _MINDPOWER::LWIRESOURCEMGR_ struct MindPower::lwIResourceMgr:MindPower::lwInterface { //57  }; #endif #ifndef _MINDPOWER::LWISCENEMGR_ #define _MINDPOWER::LWISCENEMGR_ struct MindPower::lwISceneMgr:MindPower::lwInterface { //15  }; #endif #ifndef _MINDPOWER::LWLINKCTRL_ #define _MINDPOWER::LWLINKCTRL_ struct MindPower::lwLinkCtrl { //3  }; #endif #include lwitypes2.h #ifndef _STD::ALLOCATOR<STD::BASIC_STRING<CHAR,STD::CHAR_TRAITS<CHAR>,STD::ALLOCATOR<CHAR> > >::REBIND<T>_ #define _STD::ALLOCATOR<STD::BASIC_STRING<CHAR,STD::CHAR_TRAITS<CHAR>,STD::ALLOCATOR<CHAR> > >::REBIND<T>_ struct std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >::rebind<T> { typedef std::allocator<std::_List_nod<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >::_Node *> other; }; #endif #ifndef _MINDPOWER::LWIPRIMITIVE_ #define _MINDPOWER::LWIPRIMITIVE_ struct MindPower::lwIPrimitive:MindPower::lwInterface { //46  }; #endif #include d3dx8math.h #ifndef _STD::_NUM_FLOAT_BASE_ #define _STD::_NUM_FLOAT_BASE_ struct std::_Num_float_base:std::_Num_base { //16 - }; #endif #ifndef _MINDPOWER::LWIITEM_ #define _MINDPOWER::LWIITEM_ struct MindPower::lwIItem:MindPower::lwInterface { //26  }; #endif #ifndef _MINDPOWER::LWITEM_ #define _MINDPOWER::LWITEM_ struct MindPower::lwItem:MindPower::lwIItem { //12  //34  }; #endif #endif
      
      





主な間違い:名前空間がなく、標準テンプレート用のフィルターがなく、ライブラリ接続に置き換えられない、内部ファイル構造がない、作成者がたわごとコードなどを生成しない 要するに、まだ閉塞があります。 現時点ではこれですべてです。ジェネレーターコードを添付します。誰かに役立つかもしれません。

Githubアマチュアコードジェネレーター



そのようなこと。



All Articles