前文再续,书接上一回。
破解步骤二——代码分析:
在跟踪过程发现,RMReport对打印的限制来自于rm_class.dcu文件,通过Dcu2Pas对rm_class.dcu反翻译得到_DoPrintReport函数的汇编源码,再结合D6对汇编代码的跟踪,得到如下的关键源码段:
- procedure_DoPrintReport;
- var
- i:Integer;
- j:Integer;
- lipgList:TStringList;
- lPrinter:TRMPrinter;
- liNeedNewPage:Boolean;
- lFactorX:Double;
- lFactorY:Double;
- lSavePrintInfo:TRMPageInfo;
- lOldPageNumber:Integer;
- lPageWidth:Integer;
- lPageHeight:Integer;
- asm
- @@474:{8D5358}leaedx,[ebx+$58]
- @@477:{8B45F0}moveax,[ebp-$10]
- @@480:{E800000000}callTRMPrinter.FillPrinterInfo
- @@485:{8B45F0}moveax,[ebp-$10]
- @@488:{E800000000}callTRMCustomPrinter.BeginDoc
- @@493:{8B4508}moveax,[ebp+$08]
- @@496:{80780C00}cmpbyteptr[eax+$0C],$00
- @@500:{744D}jz@@579
- ---------------------------------------------------------------------好戏开场,逐份打印方式
- @@502:{33DB}xorebx,ebx
- @@504:{EB33}jmp@@557
- @@506:{55}pushebp -----12F56C
- @@507:{33C0}xoreax,eax
- @@509:{E800000000}call_CanPrint ------EAX=1,EBX=0,ECX=0,EDX=12F504
- @@514:{59}popecx
- @@515:{84C0}testal,al -----if_CanPrintthen_PrintOnePage(....)
- @@517:{7409}jz@@528
- @@519:{55}pushebp
- @@520:{33C0}xoreax,eax
- @@522:{E800000000}call_PrintOnePage -----EAX=12F56C,ECX=64,EDX=0
- @@527:{59}popecx
- @@528:{55}pushebp
- @@529:{B801000000}moveax,$00000001 ----打印份数
- @@534:{E800000000}call_CanPrint ------EAX=1,EBX=1,ECX=0,EDX=12F504
- @@539:{59}popecx
- @@540:{84C0}testal,al -----if_CanPrintthen_PrintOnePage(....)
- @@542:{740C}jz@@556
- @@544:{55}pushebp
- @@545:{B801000000}moveax,$00000001
- @@550:{E800000000}call_PrintOnePage
- @@555:{59}popecx
- @@556:{43}incebx ----i++?/j++?
- @@557:{8B4508}moveax,[ebp+$08]
- @@560:{3B58F4}cmpebx,[eax-$0C]
- @@563:{7D72}jnl@@679 -----while(i<??)
- @@565:{8B4508}moveax,[ebp+$08]
- @@568:{8B40F8}moveax,[eax-$08]
- @@571:{80783000}cmpbyteptr[eax+$30],$00 ------此处判断了一个Cancel或Terminate标记,用户点击ProgressForm的Cancel按钮时终止打印
- @@575:{74B9}jz@@506
- @@577:{EB64}jmp@@679
- ----------------------------------------------------------------逐页打印方式
- @@579:{55}pushebp
- @@580:{33C0}xoreax,eax
- @@582:{E800000000}call_CanPrint
- @@587:{59}popecx
- @@588:{84C0}testal,al
- @@590:{7422}jz@@626
- @@592:{33DB}xorebx,ebx
- @@594:{EB0A}jmp@@606
- @@596:{55}pushebp
- @@597:{33C0}xoreax,eax
- @@599:{E800000000}call_PrintOnePage
- @@604:{59}popecx
- @@605:{43}incebx
- @@606:{8B4508}moveax,[ebp+$08]
- @@609:{3B58F4}cmpebx,[eax-$0C]
- @@612:{7D0C}jnl@@626
- @@614:{8B4508}moveax,[ebp+$08]
- @@617:{8B40F8}moveax,[eax-$08]
- @@620:{80783000}cmpbyteptr[eax+$30],$00
- @@624:{74E2}jz@@596
- @@626:{55}pushebp
- @@627:{B801000000}moveax,$00000001
- @@632:{E800000000}call_CanPrint
- @@637:{59}popecx
- @@638:{84C0}testal,al
- @@640:{7425}jz@@679
- @@642:{33DB}xorebx,ebx
- @@644:{EB0D}jmp@@659
- @@646:{55}pushebp
- @@647:{B801000000}moveax,$00000001
- @@652:{E800000000}call_PrintOnePage
- @@657:{59}popecx
- @@658:{43}incebx
- @@659:{8B4508}moveax,[ebp+$08]
- @@662:{3B58F4}cmpebx,[eax-$0C]
- @@665:{7D0C}jnl@@679
- @@667:{8B4508}moveax,[ebp+$08]
- @@670:{8B40F8}moveax,[eax-$08]
- @@673:{80783000}cmpbyteptr[eax+$30],$00
- @@677:{74DF}jz@@646
- @@679:---------------------------------------以下是清场代码,略过。
从上面的源码段中可以联想到原来的Delphi代码类似于:
文章出自:《编程手札》http://blog.youkuaiyun.com/nhconch
作者:狂歌痛饮
请从《编程手札》阅读原文,引用或转载可能导致内容不全。
- procedure_DoPrintReport;
- var
- i:Integer;
- begin
- if逐份打印then
- begin
- while(notUserCancel)do
- begin
- ifCanPrint(0)thenPrintOnePage(0);
- ifCanPrint(1)thenPrintOnePage(1);
- break;
- end;
- end
- elsebegin
- //逐页打印略……
- end;
- end;
经过分析其中的CanPrint函数,是用于对用户在打印对话框中设定的页码打印范围作判断,以决定指定页码是否能打印的,而在循环中的那两句连续的PrintOnePage才是限制所在,很明显在一次循环内连续调用两次打印功能输出两页纸是比较反常的做法,由此可以推测控件作者在正式版和试用版中使用的是同一套代码,只是在试用版中注释掉一部分代码又加了几段限制代码,而主体的功能并没作删剪,这就为破解提供了可能。
破解步骤三——代码重建:
在此需要将限制的代码恢复(改变)成原来正常的代码,正常打印的Pascal代码应该如下所示:
- procedure_DoPrintReport;
- var
- i,j:integer;
- begin
- if逐份打印then
- begin
- i:=0;
- repeat
- ifCanPrint(i)thenPrintOnePage(i);
- i:=i+1;
- until((i>=TRMEndPages.GetCount-1)or(UserCancel));
- end
- elsebegin
- //逐页打印
- fori:=0toTRMEndPages.GetCount-1do
- forj:=0tocopies{打印份数}do
- begin
- ifCanPrint(i)thenPrintOnePage(i);
- ifUserCancelthenBreak;
- end;
- end;
- end;