C++逆向随笔

C++逆向随笔

看到什么想到什么,就记录什么。

C++构造函数初始化对象

C++最具代表性的逆向点自然少不了类创建对象,类创建对象会自动调用其自身的构造函数,完成对象初始化,包括初始化赋值虚函数表,成员赋值等,用以下示例代码为例,示例代码摘自DirectX12龙书第四章Direct3D初始化。

分析的源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//D3DApp 类
class D3DApp
{
protected:

D3DApp(HINSTANCE hInstance);
D3DApp(const D3DApp& rhs) = delete;
D3DApp& operator=(const D3DApp& rhs) = delete;
virtual ~D3DApp();

public:

static D3DApp* GetApp();

HINSTANCE AppInst()const;
HWND MainWnd()const;
float AspectRatio()const;

bool Get4xMsaaState()const;
void Set4xMsaaState(bool value);

int Run();

virtual bool Initialize();
virtual LRESULT MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

protected:
virtual void CreateRtvAndDsvDescriptorHeaps();
virtual void OnResize();
virtual void Update(const GameTimer& gt)=0;
virtual void Draw(const GameTimer& gt)=0;

// Convenience overrides for handling mouse input.
virtual void OnMouseDown(WPARAM btnState, int x, int y){ }
virtual void OnMouseUp(WPARAM btnState, int x, int y) { }
virtual void OnMouseMove(WPARAM btnState, int x, int y){ }

protected:

bool InitMainWindow();
bool InitDirect3D();
void CreateCommandObjects();
void CreateSwapChain();

void FlushCommandQueue();

ID3D12Resource* CurrentBackBuffer()const;
D3D12_CPU_DESCRIPTOR_HANDLE CurrentBackBufferView()const;
D3D12_CPU_DESCRIPTOR_HANDLE DepthStencilView()const;

void CalculateFrameStats();

void LogAdapters();
void LogAdapterOutputs(IDXGIAdapter* adapter);
void LogOutputDisplayModes(IDXGIOutput* output, DXGI_FORMAT format);

protected:

static D3DApp* mApp;

HINSTANCE mhAppInst = nullptr; // application instance handle
HWND mhMainWnd = nullptr; // main window handle
bool mAppPaused = false; // is the application paused?
bool mMinimized = false; // is the application minimized?
bool mMaximized = false; // is the application maximized?
bool mResizing = false; // are the resize bars being dragged?
bool mFullscreenState = false;// fullscreen enabled

// Set true to use 4X MSAA (?.1.8). The default is false.
bool m4xMsaaState = false; // 4X MSAA enabled
UINT m4xMsaaQuality = 0; // quality level of 4X MSAA

// Used to keep track of the 揹elta-time?and game time (?.4).
GameTimer mTimer;

Microsoft::WRL::ComPtr<IDXGIFactory4> mdxgiFactory;
Microsoft::WRL::ComPtr<IDXGISwapChain> mSwapChain;
Microsoft::WRL::ComPtr<ID3D12Device> md3dDevice;

Microsoft::WRL::ComPtr<ID3D12Fence> mFence;
UINT64 mCurrentFence = 0;

Microsoft::WRL::ComPtr<ID3D12CommandQueue> mCommandQueue;
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> mDirectCmdListAlloc;
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> mCommandList;

static const int SwapChainBufferCount = 2;
int mCurrBackBuffer = 0;
Microsoft::WRL::ComPtr<ID3D12Resource> mSwapChainBuffer[SwapChainBufferCount];
Microsoft::WRL::ComPtr<ID3D12Resource> mDepthStencilBuffer;

Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mRtvHeap;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mDsvHeap;

D3D12_VIEWPORT mScreenViewport;
D3D12_RECT mScissorRect;

UINT mRtvDescriptorSize = 0;
UINT mDsvDescriptorSize = 0;
UINT mCbvSrvUavDescriptorSize = 0;

// Derived class should set these in derived constructor to customize starting values.
std::wstring mMainWndCaption = L"d3d App";
D3D_DRIVER_TYPE md3dDriverType = D3D_DRIVER_TYPE_HARDWARE;
DXGI_FORMAT mBackBufferFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
DXGI_FORMAT mDepthStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
int mClientWidth = 800;
int mClientHeight = 600;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//InitDirect3DApp类 继承自D3DApp类
class InitDirect3DApp : public D3DApp
{
public:
InitDirect3DApp(HINSTANCE hInstance);
~InitDirect3DApp();

virtual bool Initialize()override;

private:
virtual void OnResize()override;
virtual void Update(const GameTimer& gt)override;
virtual void Draw(const GameTimer& gt)override;

};

InitDirect3DApp类创建theApp对象源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
PSTR cmdLine, int showCmd)
{
// Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

try
{
InitDirect3DApp theApp(hInstance);
if(!theApp.Initialize())
return 0;

return theApp.Run();
}
catch(DxException& e)
{
MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
return 0;
}
}

分析的伪代码

InitDirect3DApp类创建theApp对象伪代码片段

DX12Init_1

InitDirect3DObject中是InitDirect3DApp类的构造函数,在其内部调用了其父类D3DApp的构造函数:

DX12Init_2

D3DAppObject即为D3DApp的构造函数,*v6=0ff_14004CD58是将子类InitDirect3DApp的虚函数表地址覆盖掉了D3DApp父类的虚函数表。

DX12Init_3

如上图,在D3DApp类的构造函数中(QWORD )v8 = off_140048148,赋予的是父类D3DApp的虚函数表地址。

父类D3DApp的虚函数表虚函数布局源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected:
......
virtual ~D3DApp();
......
public:
......
virtual bool Initialize();
virtual LRESULT MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

protected:
virtual void CreateRtvAndDsvDescriptorHeaps();
virtual void OnResize();
virtual void Update(const GameTimer& gt)=0;
virtual void Draw(const GameTimer& gt)=0;

// Convenience overrides for handling mouse input.
virtual void OnMouseDown(WPARAM btnState, int x, int y){ }
virtual void OnMouseUp(WPARAM btnState, int x, int y) { }
virtual void OnMouseMove(WPARAM btnState, int x, int y){ }

父类D3DApp的虚函数表虚函数布局伪代码:

DX12Init_4

上图已经处理过命名,和源代码进行比对,布局和源代码完全一致。

子类InitDirect3DApp的虚函数表虚函数布局源代码:

1
2
3
4
5
6
7
8
9
10
public:
InitDirect3DApp(HINSTANCE hInstance);
~InitDirect3DApp();

virtual bool Initialize()override;

private:
virtual void OnResize()override;
virtual void Update(const GameTimer& gt)override;
virtual void Draw(const GameTimer& gt)override;

子类InitDirect3DApp的虚函数表虚函数布局伪代码:

DX12Init_5

子类中~InitDirect3DApp析构函数和父类~D3DApp析构函数不一致,函数地址不同。

子类中Initialize,OnResize,Update,Draw四个函数后有override标志,确保该函数为虚函数并覆写来自基类的虚函数,函数地址不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bool InitDirect3DApp::Initialize()
{
if(!D3DApp::Initialize())
return false;

return true;
}

bool D3DApp::Initialize()
{
if(!InitMainWindow())
return false;

if(!InitDirect3D())
return false;

// Do the initial resize code.
OnResize();

return true;
}

子类中InitDirect3DApp::Initialize()函数与D3DApp:Initialize()函数不同。

1
2
3
4
void InitDirect3DApp::OnResize()
{
D3DApp::OnResize();
}

OnResize函数,子类调用了父类的OnResize函数。

1
2
3
4
void InitDirect3DApp::Update(const GameTimer& gt)
{

}

Update函数,子类中有定义,父类中无定义,仅有声明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void InitDirect3DApp::Draw(const GameTimer& gt)
{
// Reuse the memory associated with command recording.
// We can only reset when the associated command lists have finished execution on the GPU.
ThrowIfFailed(mDirectCmdListAlloc->Reset());

// A command list can be reset after it has been added to the command queue via ExecuteCommandList.
// Reusing the command list reuses memory.
ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));

// Indicate a state transition on the resource usage.
mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));

// Set the viewport and scissor rect. This needs to be reset whenever the command list is reset.
mCommandList->RSSetViewports(1, &mScreenViewport);
mCommandList->RSSetScissorRects(1, &mScissorRect);

// Clear the back buffer and depth buffer.
mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);

// Specify the buffers we are going to render to.
mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());

// Indicate a state transition on the resource usage.
mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));

// Done recording commands.
ThrowIfFailed(mCommandList->Close());

// Add the command list to the queue for execution.
ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);

// swap the back and front buffers
ThrowIfFailed(mSwapChain->Present(0, 0));
mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;

// Wait until frame commands are complete. This waiting is inefficient and is
// done for simplicity. Later we will show how to organize our rendering code
// so we do not have to wait per frame.
FlushCommandQueue();
}

Draw函数,子类中有定义,父类中无定义。

MsgProc,CreateDesHeaps,OnMouseDown,OnMouseUp,OnMouseMove五个函数,子类没有重定义,函数地址相同。

————————————————————————-分界线————————————————————————-

上面是说虚函数,下面是紧接着对应的对象成员布局,伪代码成员布局与源代码布局一致(一开始贴了),成员和成员之间遵循内存对齐的原则,下图直观(看不清的话,f12打开console,查看原图):

DX12Init_6

以上就是编译好的程序中对象的内存布局,所有的公有函数,保护函数,私有函数都是直接调用的形式,不占用对象的内存空间。