RMReport3.51破解手札㈢
来源:互联网 发布:base64转化为json格式 编辑:程序博客网 时间:2024/05/21 09:01
破解步骤三——代码重建:
在此需要将限制的代码恢复(改变)成原来正常的代码,正常打印的Pascal代码应该如下所示:
文章出自:《编程手札》http://blog.csdn.net/nhconch
作者:狂歌痛饮
请从《编程手札》阅读原文,引用或转载可能导致内容不全。
根据Pascal代码可以很轻易的写出对应的汇编代码:
<script type="text/javascript"><!--google_ad_client = "pub-5395599807454886";/* 468x60, 创建于 08-12-15 */google_ad_slot = "2456405239";google_ad_width = 468;google_ad_height = 60;//--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
要把这段汇编代码填回原来的DCU里还存在两个问题:第一问题是,在DCU中,所有的Call XXXXX调用的机器码都是E8 00 00 00 00,也就是说Call的地址静态时全是00,在联编过程才将00替换成正确的地址写入到可执行文件中,如果直接修改了DCU文件,那么在联编过程中编译器依然试图进行地址替换,这将会破坏掉破解的代码段而产生不可知结果,所以编写破解代码时一方面必须绕开相应位置,避免被编译器破坏代码;另一方面,又需要充分利用编译器替换的结果,使破解代码能正确调用相应函数。于是便有了下面这段代码:
但是这段代码却多了19个字节,没法填回到DCU中。
文章出自:《编程手札》http://blog.csdn.net/nhconch
作者:狂歌痛饮
请从《编程手札》阅读原文,引用或转载可能导致内容不全。
第二个问题是,原来的汇编码中没有对TRMEndPages.GetCount的调用,编译器不知道要为可执行文件生成此函数的调用地址,因此必须另辟蹊径实现GetCount的功能。通过对GetCount函数的代码的分析(过程略),通过以下一段代码实现了GetCount函数的功能:
综合以上问题,我写下第三段破解代码:
文章出自:《编程手札》http://blog.csdn.net/nhconch
作者:狂歌痛饮
请从《编程手札》阅读原文,引用或转载可能导致内容不全。
这段代码中裁剪掉了逐份打印功能(实际中也很少有人使用)以便有足够的空间书写代码,而实际证明这段代码工作得相当好。剩下的事就是把破解代码转换成机器码、用十六进制编辑器(UtralEdit、HexEdit、或更旧的PCToools等),把rm_Class.dcu中的代码替换为破解代码(rm3.51的偏移值为48EE7),方法很多这里不作述说。
在此需要将限制的代码恢复(改变)成原来正常的代码,正常打印的Pascal代码应该如下所示:
- procedure _DoPrintReport;
- var
- i,j: integer;
- begin
- if 逐份打印 then
- begin
- i := 0;
- repeat
- if CanPrint(i) then PrintOnePage(i);
- i := i+1;
- until ((i>=TRMEndPages.GetCount-1) or (UserCancel));
- end
- else begin
- //逐页打印
- for i:=0 to TRMEndPages.GetCount-1 do
- for j:=0 to copies{打印份数} do
- begin
- if CanPrint(i) then PrintOnePage(i);
- if UserCancel then Break;
- end;
- end;
- end;
作者:狂歌痛饮
请从《编程手札》阅读原文,引用或转载可能导致内容不全。
- //第一段
- asm
- mov eax, [ebp + $08]
- cmp byte ptr [eax + $0C], $00 //判断是否逐份打印
- jz @@579 //不是转到逐页打印
- //`````````````````逐份打印`````````````````````````````
- xor ebx, ebx //ebx保存当前打印份数
- jmp @@557
- @@506:
- mov eax, [ebp + $08]
- mov eax, [eax - $08]
- mov eax, [eax + $58]
- call TRMEndPages.GetCount //取总页数
- dec eax //eax=页数-1
- mov ecx, eax //ecx保存循环次数
- xor eax, eax //eax保存当前打印页码
- @@1:
- push ecx
- push eax
- push ebp
- call _CanPrint
- test al, al //判断是否要打印
- jz @@528
- pop ecx {push ebp}
- pop eax
- push eax
- push ebp
- call _PrintOnePage
- @@528:
- pop ecx {push ebp}
- pop eax
- pop ecx
- inc eax
- loop @@1
- inc ebx //打印份数加1
- @@557:
- mov eax, [ebp + $08]
- cmp ebx, [eax - $0c] //对比打印份数
- jnl @@679 //打完退出
- mov eax, [ebp + $08]
- mov eax, [eax - $08]
- cmp byte ptr [eax + $30], $00 //查看是否要终止
- jz @@506 //不是继续
- jmp @@679 //终止退出
- //`````````````````逐页打印`````````````````````````````
- @@579:
- mov eax, [ebp + $08]
- mov eax, [eax - $08]
- mov eax, [eax + $58]
- call TRMEndPages.GetCount //取总页数
- or eax, eax
- jz @@679 //页数为0时直接退出
- dec eax
- mov ecx, eax //ecx保存页数
- xor eax, eax //eax保存当前打印页码
- @@2Check_and_print:
- push ecx //保存循环次数(页数)
- push eax //保存当前页码
- xor ebx, ebx //ebx保存当前打印份数
- push ebp
- call _CanPrint //Tips:影响eax, ecx, edx
- pop ecx {push ebp}
- test al, al
- jz @@2Print_next_page
- @@2PrintOut:
- pop eax //取当前页码
- push eax
- push ebp
- call _PrintOnePage //Tips:影响eax, ecx
- pop ecx {push ebp}
- @@2Check_terminated_flag:
- mov eax, [ebp + $08]
- mov eax, [eax - $08]
- cmp byte ptr [eax + $30], $00
- jnz @@2Exit
- @@2Check_copies:
- inc ebx //份数加1
- mov eax, [ebp + $08]
- cmp ebx, [eax - $0C]
- jl @@2PrintOut //继续打印
- @@2Print_next_page:
- pop eax //取回页数和页码
- pop ecx
- inc eax
- loop @@2Check_and_print
- jmp @@679
- @@2Exit:
- pop eax //平衡堆栈
- pop eax
- jmp @@679 //退出
- @@679:
- nop
- end;
要把这段汇编代码填回原来的DCU里还存在两个问题:第一问题是,在DCU中,所有的Call XXXXX调用的机器码都是E8 00 00 00 00,也就是说Call的地址静态时全是00,在联编过程才将00替换成正确的地址写入到可执行文件中,如果直接修改了DCU文件,那么在联编过程中编译器依然试图进行地址替换,这将会破坏掉破解的代码段而产生不可知结果,所以编写破解代码时一方面必须绕开相应位置,避免被编译器破坏代码;另一方面,又需要充分利用编译器替换的结果,使破解代码能正确调用相应函数。于是便有了下面这段代码:
- //第二段
- asm
- mov eax, [ebp + $08]
- cmp byte ptr [eax + $0C], $00 //判断是否逐份打印
- jz @@579 //不是转到逐页打印
- //`````````````````逐份打印`````````````````````````````
- xor ebx, ebx //ebx保存当前打印份数
- jmp @@557
- {proc near }@@_IsCanPrint:
- nop
- nop
- push ebp
- db $E8, $00, $00, $00, $00 //call _CanPrint
- pop edx
- ret
- {end proc}
- {proc near}@@_Pages_GetCount:
- mov eax, [ebp + $08]
- jmp @@_Pages_GetCount_Block2
- //----------------------------
- {proc near }@@_PrintAPage:
- push ebp
- db $E8, $00, $00, $00, $00 //call _PrintOnePage
- pop ecx
- ret
- {end proc}
- //-----------------------------
- @@_Pages_GetCount_Block2:
- mov eax, [eax - $08]
- jmp @@_Pages_GetCount_Block3
- db $E8, $00, $00, $00, $00 //第二处call _CanPrint,必须跳过
- @@_Pages_GetCount_Block3:
- mov eax, [eax + $58]
- mov eax, [eax + $08]
- mov eax, [eax + $08]
- dec eax
- ret
- {end proc}
- @@57:
- db $E8, $00, $00, $00, $00 //第二处call _PrintOnePage,必须跳过
- @@506:
- call @@_Pages_GetCount
- //or eax, eax
- //jz @@679 //页数为0时直接退出
- //dec eax //eax=页数-1
- mov ecx, eax //ecx保存循环次数
- xor eax, eax //eax保存当前打印页码
- @@1:
- push ecx
- push eax
- call @@_IsCanPrint
- test al, al //判断是否要打印
- jz @@528
- pop eax
- push eax
- jmp @@1_2
- nop
- nop
- nop
- db $E8, $00, $00, $00, $00 //第三处call _CanPrint,必须跳过
- @@1_2:
- call @@_PrintAPage
- @@528:
- pop eax
- pop ecx
- inc eax
- loop @@1
- inc ebx //打印份数加1
- jmp @@1_3
- db $00, $00, $00, $00 //第三处call _PrintOnePage,必须跳过
- @@1_3:
- @@557:
- mov eax, [ebp + $08]
- cmp ebx, [eax - $0c] //对比打印份数
- jnl @@679 //打完退出
- //mov eax, [ebp + $08]
- mov eax, [eax - $08]
- cmp byte ptr [eax + $30], $00 //查看是否要终止
- jz @@506 //不是继续
- jmp @@679 //终止退出
- //`````````````````逐页打印`````````````````````````````
- @@579:
- (* mov eax, [ebp + $08]
- mov eax, [eax - $08]
- mov eax, [eax + $58]
- db $E8, $00, $00, $00, $00 //call TRMEndPages.GetCount //取总页数
- or eax, eax
- jz @@679 //页数为0时直接退出
- dec eax
- *)
- call @@_Pages_GetCount //取总页数
- mov ecx, eax //ecx保存页数
- jmp @@2_1
- db $E8, $00, $00, $00, $00 //第四处call _CanPrint,必须跳过
- @@2_1:
- xor eax, eax //eax保存当前打印页码
- @@2Check_and_print:
- push ecx //保存循环次数(页数)
- push eax //保存当前页码
- xor ebx, ebx //ebx保存当前打印份数
- (* push ebp
- db $E8, $00, $00, $00, $00 //call _CanPrint //Tips:影响eax, ecx, edx
- pop ecx {push ebp}
- *)
- call @@_IsCanPrint
- test al, al
- jmp @@2_2
- db $E8, $00, $00, $00, $00 //第四处call _PrintOnePage,必须跳过
- @@2_2:
- jz @@2Print_next_page
- @@2PrintOut:
- pop eax //取当前页码
- push eax
- (* push ebp
- db $E8, $00, $00, $00, $00 //call _PrintOnePage//Tips:影响eax, ecx
- pop ecx {push ebp}
- *)
- call @@_PrintAPage
- @@2Check_terminated_flag:
- mov eax, [ebp + $08]
- mov eax, [eax - $08]
- cmp byte ptr [eax + $30], $00
- jnz @@2Exit
- @@2Check_copies:
- inc ebx //份数加1
- mov eax, [ebp + $08]
- cmp ebx, [eax - $0C]
- jl @@2PrintOut //继续打印
- @@2Print_next_page:
- pop eax //取回页数和页码
- pop ecx
- inc eax
- loop @@2Check_and_print
- jmp @@679
- @@2Exit:
- pop eax //平衡堆栈
- pop eax
- jmp @@679 //退出
- @@679:
- db $90, $90, $90
- end;
文章出自:《编程手札》http://blog.csdn.net/nhconch
作者:狂歌痛饮
请从《编程手札》阅读原文,引用或转载可能导致内容不全。
- //GetCount
- mov eax, [ebp + $08]
- mov eax, [eax - $08]
- mov eax, [eax + $58]
- mov eax, [eax + $08]
- mov eax, [eax + $08]
- //ret
- asm
- mov eax, [ebp + $08]
- cmp [eax - $0C], $00
- je @@2Go679 //份数为0时直接退出
- jmp @@579
- @@_IsCanPrint:
- push ebp
- db $E8, $00, $00, $00, $00 //call _CanPrint //Tips:影响eax, ecx, edx
- pop ecx {push ebp}
- test al, al
- jz @@2Print_next_page
- @@_PrintAPage:
- pop eax //取当前页码
- push eax
- push ebp
- db $E8, $00, $00, $00, $00 //call _PrintOnePage//Tips:影响eax, ecx
- pop ecx
- jmp @@2Check_terminated_flag
- dd 0
- db $E8, $00, $00, $00, $00 //跳过第二处call _CanPrint
- @@579:
- mov eax, [ebp + $08]
- mov eax, [eax - $08]
- mov eax, [eax + $58]
- jmp @@2Skip1
- db $E8, $00, $00, $00, $00 //跳过第二处call _PrintOnePage
- @@2Skip1:
- mov eax, [eax + $08]
- mov eax, [eax + $08] //TRMEndPages.GetCount //取总页数
- or eax, eax
- jz @@2Go679 //页数为0时直接退出
- dec eax
- mov ecx, eax //ecx保存页数
- xor eax, eax //eax保存当前打印页码
- @@2Check_and_print:
- push ecx //保存循环次数(页数)
- push eax //保存当前页码
- xor ebx, ebx //ebx保存当前打印份数
- jmp @@_IsCanPrint
- dw 0, 0, 0
- db $E8, $00, $00, $00, $00 //跳过第三处call _CanPrint
- dd 0, 0, 0
- db $E8, $00, $00, $00, $00 //跳过第三处call _PrintOnePage
- @@2Check_terminated_flag:
- mov eax, [ebp + $08]
- mov eax, [eax - $08]
- cmp byte ptr [eax + $30], $00
- jnz @@2Exit
- @@2Check_copies:
- inc ebx //份数加1
- mov eax, [ebp + $08]
- cmp ebx, [eax - $0C]
- jl @@_PrintAPage //继续打印
- @@2Print_next_page:
- pop eax //取回页数和页码
- pop ecx
- inc eax
- loop @@2Check_and_print
- jmp @@2Go679
- db $E8, $00, $00, $00, $00 //跳过第四处call _CanPrint
- @@2Exit:
- pop eax //平衡堆栈
- pop eax
- @@2Go679: //通过此处跳到@@679,因编译器忽略jmp word ptr ..
- nop //空指令,避免编译器优化代码
- jmp @@679 //到@@679退出
- dd 0, 0, 0, 0, 0, 0, 0, 0, 0
- db 0
- @@679:
- inc eax
- end;
作者:狂歌痛饮
请从《编程手札》阅读原文,引用或转载可能导致内容不全。
RMReport3.51破解手札㈠ RMReport3.51破解手札㈡
- RMReport3.51破解手札㈢
- RMReport3.51破解手札㈠
- RMReport3.51破解手札㈡
- 培训手札
- 菜鸟手札
- 兼容手札
- jquery手札
- vi 手札
- IOS手札
- beacon手札
- 软件工程手札
- 【转贴】Perl学习手札
- Struts學習手札
- Perl学习手札
- 西门子C65开发手札
- 手札第一篇。
- C#手札,第一步。
- Strust 学习手札
- maven 项目转 eclipse
- IP 限制规则
- delphi窗口的双缓冲绘制浅析
- 生理卫生课的经典对白
- 在CLUSTER环境给SQL SERVER 2008打补丁时需要注意的问题
- RMReport3.51破解手札㈢
- Effective C# 备忘
- Google Book Search APIs——谷歌图书搜索API
- SQLServer2008中恼人的"阻止保存要求重新创建表的更改"
- 关于JNI 和JAVA 编码的问题小结
- linux任务自动化 初步接触crontab和at
- ffffffffffff
- 数据窗口中各项指标的基本操作
- 人的精力是有限的