C++ command buffer
以下代码实现了一个C++ command buffer,代码在VC80调试通过,支持_cdecl,_stdcall,_thiscall三种调用
1)参数存储:为了便于参数压栈,参数采用DWORD块存储,并且按照从右到左的顺序排列
2)参数进栈:使用计数循环,让每一个DWORD进栈
3)函数执行:对于_cdecl 需要手动退栈,_stdcall 和 _thiscall 自动退栈
4)未实现 check esp 和 sse优化
1 #define OBJECT_ADDR_BIT (31)
2 #define OBJECT_ADDR_MASK (1<<OBJECT_ADDR_BIT)
3
4 #define AUTO_STACK_BIT (30)
5 #define AUTO_STACK_MASK (1<<AUTO_STACK_BIT)
6
7 #define PARAM_BLOCK_MASK (0xffff)
8
9 unsigned int command_buffer[1024*1024]={0};
10 unsigned int command_buffer_pos = 0;
11
12 void test_cmd( int a,int b)
13 {
14 int c = a+b;
15 }
16
17 void test_object_cmd( unsigned int object_addr,unsigned int func_addr,int a,int b )
18 {
19 int c = a+b;
20 }
21
22 void test_stdcall_cmd_record( int a,int b )
23 {
24 command_buffer[command_buffer_pos++] = (2&PARAM_BLOCK_MASK)|(AUTO_STACK_MASK); //参数块占有DWORD个数
25 command_buffer[command_buffer_pos++] = (unsigned int)(void*)&glVertex2i; //执行函数地址
26 /*参数块按照倒序从右往左顺序排列*/
27 command_buffer[command_buffer_pos++] = b; //参数2
28 command_buffer[command_buffer_pos++] = a; //参数1
29 }
30
31 void test_cmd_record( int a,int b )
32 {
33 command_buffer[command_buffer_pos++] = (2&PARAM_BLOCK_MASK)|(AUTO_STACK_MASK); //参数块占有DWORD个数
34 command_buffer[command_buffer_pos++] = (unsigned int)(void*)&test_cmd; //执行函数地址
35 /*参数块按照倒序从右往左顺序排列*/
36 command_buffer[command_buffer_pos++] = b; //参数2
37 command_buffer[command_buffer_pos++] = a; //参数1
38 }
39
40 void test_object_cmd_record( unsigned int object_addr,unsigned int func_addr,int a,int b)
41 {
42 command_buffer[command_buffer_pos++] = (2&PARAM_BLOCK_MASK)|OBJECT_ADDR_MASK|AUTO_STACK_MASK;//最高位表示是否包含对象地址
43 command_buffer[command_buffer_pos++] = func_addr; //执行函数地址
44 /*参数块按照倒序从右往左顺序排列*/
45 command_buffer[command_buffer_pos++] = b; //参数2
46 command_buffer[command_buffer_pos++] = a; //参数1
47 command_buffer[command_buffer_pos++] = object_addr; //对象地址
48 }
49
50 void exec_command_buffer()
51 {
52 int i = 0;
53 int c_command = 0;
54
55 while( i<command_buffer_pos )
56 {
57 /* 第一个DWORD 的高16位表示是否包含对象地址,以及是否需要自动退栈;低16位表示 参数块所占用的DWORD数量 */
58 unsigned int cc = command_buffer[i];
59
60 /* 参数块所占用的DWORD数量*/
61 int c = cc&0xffff;
62
63 /* 第31位表示是否包含对象地址,如果包含对象地址,c1将用作1个DWORD的增量 */
64 unsigned int c1 = (cc&0x80000000)>>31;
65
66 /* 第30位表示是否需要手动退栈 */
67 unsigned int c2 = (cc&0x40000000)>>30;
68
69 int func_addr = command_buffer[i+1];
70
71 /* 如果是_cdecl 调用,将用作esp增量 */
72 int n = c*4;
73
74 /* 对象地址 */
75 int obj_addr = 0;
76
77 /*判断是否包含对象地址*/
78 if( c1 )
79 {
80 /* 对象地址包含在参数块的后面 */
81 obj_addr = command_buffer[i+c+2];
82 }
83
84 _asm
85 {
86 mov eax,0
87 mov ecx,c
88 /* 参数进栈 */
89 TARGET1:
90
91 cmp eax,ecx
92 jge TARGET2
93 mov ebx,i
94 add ebx,2
95 add ebx,eax
96 /* 将一个DWORD进栈 */
97 push dword ptr command_buffer[ebx*4]
98 /* 计数循环并且跳转 TARGET1 */
99 add eax,1
100 jmp TARGET1
101 /* 处理 _thiscall 的对象地址 */
102 TARGET2:
103
104 mov ecx,c1
105 cmp ecx,0
106 je TARGET3
107 /* _thiscall 需要把对象地址放入ecx */
108 lea ecx,obj_addr
109 TARGET3:
110
111 call func_addr
112 /* 对于_thiscall和_stdcall不需要增加esp */
113 mov ecx,c2
114 cmp ecx,0
115 jne TARGET4
116 /* _cdecl 不需要增加esp */
117 add esp,n
118 TARGET4:
119
120 nop
121 }
122
123 /* 移动 buffer pos */
124 i += c+2+c1;
125
126 /* 命令计数*/
127 c_command++;
128 }
129 }
130
131
132
2 #define OBJECT_ADDR_MASK (1<<OBJECT_ADDR_BIT)
3
4 #define AUTO_STACK_BIT (30)
5 #define AUTO_STACK_MASK (1<<AUTO_STACK_BIT)
6
7 #define PARAM_BLOCK_MASK (0xffff)
8
9 unsigned int command_buffer[1024*1024]={0};
10 unsigned int command_buffer_pos = 0;
11
12 void test_cmd( int a,int b)
13 {
14 int c = a+b;
15 }
16
17 void test_object_cmd( unsigned int object_addr,unsigned int func_addr,int a,int b )
18 {
19 int c = a+b;
20 }
21
22 void test_stdcall_cmd_record( int a,int b )
23 {
24 command_buffer[command_buffer_pos++] = (2&PARAM_BLOCK_MASK)|(AUTO_STACK_MASK); //参数块占有DWORD个数
25 command_buffer[command_buffer_pos++] = (unsigned int)(void*)&glVertex2i; //执行函数地址
26 /*参数块按照倒序从右往左顺序排列*/
27 command_buffer[command_buffer_pos++] = b; //参数2
28 command_buffer[command_buffer_pos++] = a; //参数1
29 }
30
31 void test_cmd_record( int a,int b )
32 {
33 command_buffer[command_buffer_pos++] = (2&PARAM_BLOCK_MASK)|(AUTO_STACK_MASK); //参数块占有DWORD个数
34 command_buffer[command_buffer_pos++] = (unsigned int)(void*)&test_cmd; //执行函数地址
35 /*参数块按照倒序从右往左顺序排列*/
36 command_buffer[command_buffer_pos++] = b; //参数2
37 command_buffer[command_buffer_pos++] = a; //参数1
38 }
39
40 void test_object_cmd_record( unsigned int object_addr,unsigned int func_addr,int a,int b)
41 {
42 command_buffer[command_buffer_pos++] = (2&PARAM_BLOCK_MASK)|OBJECT_ADDR_MASK|AUTO_STACK_MASK;//最高位表示是否包含对象地址
43 command_buffer[command_buffer_pos++] = func_addr; //执行函数地址
44 /*参数块按照倒序从右往左顺序排列*/
45 command_buffer[command_buffer_pos++] = b; //参数2
46 command_buffer[command_buffer_pos++] = a; //参数1
47 command_buffer[command_buffer_pos++] = object_addr; //对象地址
48 }
49
50 void exec_command_buffer()
51 {
52 int i = 0;
53 int c_command = 0;
54
55 while( i<command_buffer_pos )
56 {
57 /* 第一个DWORD 的高16位表示是否包含对象地址,以及是否需要自动退栈;低16位表示 参数块所占用的DWORD数量 */
58 unsigned int cc = command_buffer[i];
59
60 /* 参数块所占用的DWORD数量*/
61 int c = cc&0xffff;
62
63 /* 第31位表示是否包含对象地址,如果包含对象地址,c1将用作1个DWORD的增量 */
64 unsigned int c1 = (cc&0x80000000)>>31;
65
66 /* 第30位表示是否需要手动退栈 */
67 unsigned int c2 = (cc&0x40000000)>>30;
68
69 int func_addr = command_buffer[i+1];
70
71 /* 如果是_cdecl 调用,将用作esp增量 */
72 int n = c*4;
73
74 /* 对象地址 */
75 int obj_addr = 0;
76
77 /*判断是否包含对象地址*/
78 if( c1 )
79 {
80 /* 对象地址包含在参数块的后面 */
81 obj_addr = command_buffer[i+c+2];
82 }
83
84 _asm
85 {
86 mov eax,0
87 mov ecx,c
88 /* 参数进栈 */
89 TARGET1:
90
91 cmp eax,ecx
92 jge TARGET2
93 mov ebx,i
94 add ebx,2
95 add ebx,eax
96 /* 将一个DWORD进栈 */
97 push dword ptr command_buffer[ebx*4]
98 /* 计数循环并且跳转 TARGET1 */
99 add eax,1
100 jmp TARGET1
101 /* 处理 _thiscall 的对象地址 */
102 TARGET2:
103
104 mov ecx,c1
105 cmp ecx,0
106 je TARGET3
107 /* _thiscall 需要把对象地址放入ecx */
108 lea ecx,obj_addr
109 TARGET3:
110
111 call func_addr
112 /* 对于_thiscall和_stdcall不需要增加esp */
113 mov ecx,c2
114 cmp ecx,0
115 jne TARGET4
116 /* _cdecl 不需要增加esp */
117 add esp,n
118 TARGET4:
119
120 nop
121 }
122
123 /* 移动 buffer pos */
124 i += c+2+c1;
125
126 /* 命令计数*/
127 c_command++;
128 }
129 }
130
131
132