RMReport3.51破解手札㈡

前文再续,书接上一回。

破解步骤二——代码分析:
  在跟踪过程发现,RMReport对打印的限制来自于rm_class.dcu文件,通过Dcu2Pas对rm_class.dcu反翻译得到_DoPrintReport函数的汇编源码,再结合D6对汇编代码的跟踪,得到如下的关键源码段:

  1. procedure_DoPrintReport;
  2. var
  3. i:Integer;
  4. j:Integer;
  5. lipgList:TStringList;
  6. lPrinter:TRMPrinter;
  7. liNeedNewPage:Boolean;
  8. lFactorX:Double;
  9. lFactorY:Double;
  10. lSavePrintInfo:TRMPageInfo;
  11. lOldPageNumber:Integer;
  12. lPageWidth:Integer;
  13. lPageHeight:Integer;
  14. asm
  15. @@474:{8D5358}leaedx,[ebx+$58]
  16. @@477:{8B45F0}moveax,[ebp-$10]
  17. @@480:{E800000000}callTRMPrinter.FillPrinterInfo
  18. @@485:{8B45F0}moveax,[ebp-$10]
  19. @@488:{E800000000}callTRMCustomPrinter.BeginDoc
  20. @@493:{8B4508}moveax,[ebp+$08]
  21. @@496:{80780C00}cmpbyteptr[eax+$0C],$00
  22. @@500:{744D}jz@@579
  23. ---------------------------------------------------------------------好戏开场,逐份打印方式
  24. @@502:{33DB}xorebx,ebx
  25. @@504:{EB33}jmp@@557
  26. @@506:{55}pushebp -----12F56C
  27. @@507:{33C0}xoreax,eax
  28. @@509:{E800000000}call_CanPrint ------EAX=1,EBX=0,ECX=0,EDX=12F504
  29. @@514:{59}popecx
  30. @@515:{84C0}testal,al -----if_CanPrintthen_PrintOnePage(....)
  31. @@517:{7409}jz@@528
  32. @@519:{55}pushebp
  33. @@520:{33C0}xoreax,eax
  34. @@522:{E800000000}call_PrintOnePage -----EAX=12F56C,ECX=64,EDX=0
  35. @@527:{59}popecx
  36. @@528:{55}pushebp
  37. @@529:{B801000000}moveax,$00000001 ----打印份数
  38. @@534:{E800000000}call_CanPrint ------EAX=1,EBX=1,ECX=0,EDX=12F504
  39. @@539:{59}popecx
  40. @@540:{84C0}testal,al -----if_CanPrintthen_PrintOnePage(....)
  41. @@542:{740C}jz@@556
  42. @@544:{55}pushebp
  43. @@545:{B801000000}moveax,$00000001
  44. @@550:{E800000000}call_PrintOnePage
  45. @@555:{59}popecx
  46. @@556:{43}incebx ----i++?/j++?
  47. @@557:{8B4508}moveax,[ebp+$08]
  48. @@560:{3B58F4}cmpebx,[eax-$0C]
  49. @@563:{7D72}jnl@@679 -----while(i<??)
  50. @@565:{8B4508}moveax,[ebp+$08]
  51. @@568:{8B40F8}moveax,[eax-$08]
  52. @@571:{80783000}cmpbyteptr[eax+$30],$00 ------此处判断了一个Cancel或Terminate标记,用户点击ProgressForm的Cancel按钮时终止打印
  53. @@575:{74B9}jz@@506
  54. @@577:{EB64}jmp@@679
  55. ----------------------------------------------------------------逐页打印方式
  56. @@579:{55}pushebp
  57. @@580:{33C0}xoreax,eax
  58. @@582:{E800000000}call_CanPrint
  59. @@587:{59}popecx
  60. @@588:{84C0}testal,al
  61. @@590:{7422}jz@@626
  62. @@592:{33DB}xorebx,ebx
  63. @@594:{EB0A}jmp@@606
  64. @@596:{55}pushebp
  65. @@597:{33C0}xoreax,eax
  66. @@599:{E800000000}call_PrintOnePage
  67. @@604:{59}popecx
  68. @@605:{43}incebx
  69. @@606:{8B4508}moveax,[ebp+$08]
  70. @@609:{3B58F4}cmpebx,[eax-$0C]
  71. @@612:{7D0C}jnl@@626
  72. @@614:{8B4508}moveax,[ebp+$08]
  73. @@617:{8B40F8}moveax,[eax-$08]
  74. @@620:{80783000}cmpbyteptr[eax+$30],$00
  75. @@624:{74E2}jz@@596
  76. @@626:{55}pushebp
  77. @@627:{B801000000}moveax,$00000001
  78. @@632:{E800000000}call_CanPrint
  79. @@637:{59}popecx
  80. @@638:{84C0}testal,al
  81. @@640:{7425}jz@@679
  82. @@642:{33DB}xorebx,ebx
  83. @@644:{EB0D}jmp@@659
  84. @@646:{55}pushebp
  85. @@647:{B801000000}moveax,$00000001
  86. @@652:{E800000000}call_PrintOnePage
  87. @@657:{59}popecx
  88. @@658:{43}incebx
  89. @@659:{8B4508}moveax,[ebp+$08]
  90. @@662:{3B58F4}cmpebx,[eax-$0C]
  91. @@665:{7D0C}jnl@@679
  92. @@667:{8B4508}moveax,[ebp+$08]
  93. @@670:{8B40F8}moveax,[eax-$08]
  94. @@673:{80783000}cmpbyteptr[eax+$30],$00
  95. @@677:{74DF}jz@@646
  96. @@679:---------------------------------------以下是清场代码,略过。
<!-- google_ad_client = "pub-5395599807454886"; /* 468x60, 创建于 08-12-15 */ google_ad_slot = "2456405239"; google_ad_width = 468; google_ad_height = 60; //-->
从上面的源码段中可以联想到原来的Delphi代码类似于:
文章出自:《编程手札》http://blog.csdn.net/nhconch
作者:狂歌痛饮
请从《编程手札》阅读原文,引用或转载可能导致内容不全。

  1. procedure_DoPrintReport;
  2. var
  3. i:Integer;
  4. begin
  5. if逐份打印then
  6. begin
  7. while(notUserCancel)do
  8. begin
  9. ifCanPrint(0)thenPrintOnePage(0);
  10. ifCanPrint(1)thenPrintOnePage(1);
  11. break;
  12. end;
  13. end
  14. elsebegin
  15. //逐页打印略……
  16. end;
  17. end;

  经过分析其中的CanPrint函数,是用于对用户在打印对话框中设定的页码打印范围作判断,以决定指定页码是否能打印的,而在循环中的那两句连续的PrintOnePage才是限制所在,很明显在一次循环内连续调用两次打印功能输出两页纸是比较反常的做法,由此可以推测控件作者在正式版和试用版中使用的是同一套代码,只是在试用版中注释掉一部分代码又加了几段限制代码,而主体的功能并没作删剪,这就为破解提供了可能。

破解步骤三——代码重建:
  在此需要将限制的代码恢复(改变)成原来正常的代码,正常打印的Pascal代码应该如下所示:

  1. procedure_DoPrintReport;
  2. var
  3. i,j:integer;
  4. begin
  5. if逐份打印then
  6. begin
  7. i:=0;
  8. repeat
  9. ifCanPrint(i)thenPrintOnePage(i);
  10. i:=i+1;
  11. until((i>=TRMEndPages.GetCount-1)or(UserCancel));
  12. end
  13. elsebegin
  14. //逐页打印
  15. fori:=0toTRMEndPages.GetCount-1do
  16. forj:=0tocopies{打印份数}do
  17. begin
  18. ifCanPrint(i)thenPrintOnePage(i);
  19. ifUserCancelthenBreak;
  20. end;
  21. end;
  22. end;
RMReport3.51破解手札㈠    RMReport3.51破解手札㈢

你可能感兴趣的:(编程,Google,J#,Delphi,pascal)