-
破解初级教程 初学准备入门者学习
2007-06-01 01:23:43
破解初级教程 初学准备入门者学习
第一课 壳
************
一.壳的概念
作者编好软件后,编译成exe可执行文件
1.有一些版权信息需要保护起来,不想让别人
随便改动,如作者的姓名等
2.需要把程序搞的小一点,从而方便使用
于是,需要用到一些软件,他们能将exe可执行文件压缩,
实现上述两个功能,这些软件称为加壳软件或压缩软件.
它不同于一般的winzip,winrar等压缩软件.
它是压缩exe可执行文件的,压缩后的文件可以直接运行.
二.加壳软件
最常见的加壳软件ASPACK ,UPX,PEcompact
不常用的加壳软件WWPACK32;PE-PACK ;PETITE ;NEOLITE
三.侦测壳和软件所用编写语言的软件
1.侦测壳的软件fileinfo.exe 简称fi.exe(侦测壳的能力极强)
使用方法:
第一种:待侦测壳的软件(如aa.exe)和fi.exe位于同一目录下,执行
windows起始菜单的运行,键入
fi aa
第二种:待侦测壳的软件(如aa.exe)和fi.exe位于同一目录下,将aa的图标拖到fi的图标上
2.侦测壳和软件所用编写语言的软件language.exe(两个功能
合为一体,很棒) 推荐language2000中文版,我的主页可下载
傻瓜式软件,运行后选取待侦测壳的软件即可(open)
[ 本帖最后由 渔歌子 于 2005-12-23 00:02 编辑 ]
第二课 脱壳
************
拿到一个软件,我们首先根据第一课的内容
侦测它的壳,然后我们要把它的壳脱去,还原它的
本来面目.若它没有加壳,就省事不用脱壳了.
一.脱壳软件
unaspack,caspr,upx,unpecompact,procdump
二.使用方法
(一)aspack壳 脱壳可用unaspack或caspr
1.unaspack 我的主页可下载中文版
使用方法类似lanuage
傻瓜式软件,运行后选取待脱壳的软件即可. 缺点:只能脱aspack早些时候版本的壳,不能脱高版本的壳
2.caspr
第一种:待脱壳的软件(如aa.exe)和caspr.exe位于同一目录下,执行
windows起始菜单的运行,键入 caspr aa.exe
脱壳后的文件为aa.ex_,删掉原来的aa.exe,将aa.ex_改名为aa.exe即可
使用方法类似fi 优点:可以脱aspack任何版本的壳,脱壳能力极强 缺点:Dos界面
第二种:将aa.exe的图标拖到caspr.exe的图标上
***若已侦测出是aspack壳,用unaspack脱壳出错,说明是aspack高版本的壳,用caspr脱即可
(二)upx壳 脱壳可用upx
待脱壳的软件(如aa.exe)和upx.exe位于同一目录下,执行
windows起始菜单的运行,键入
upx -d aa.exe
(三)PEcompact壳 脱壳用unpecompact 我的主页可下载中文版
使用方法类似lanuage
傻瓜式软件,运行后选取待脱壳的软件即可
(四)procdump 万能脱壳但不精,一般不要用 我的主页可下载中文版
使用方法:运行后,先指定壳的名称,再选定欲脱壳软件,确定即可
脱壳后的文件大于原文件
由于脱壳软件很成熟,手动脱壳一般用不到,不作介绍.
以上工具的下载地址见第一课
三. exe可执行文件编辑软件ultraedit
下载它的汉化版本,它的注册机可从网上搜到
ultraedit打开一个中文软件,若加壳,许多汉字不能被认出
ultraedit打开一个中文软件,若未加壳或已经脱壳,许多汉字能被认出
ultraedit可用来检验壳是否脱掉,以后它的用处还很多,请熟练掌握
例如,可用它的替换功能替换作者的姓名为你的姓名
注意字节必须相等,两个汉字替两个,三个替三个,不足处在ultraedit编辑器左边用00补
四作业
1.下载上面提到的软件,熟练掌握以上软件的使用
2.下载软件,脱壳,多练习
3.结合我讲的,看一下看雪教程的相关内容,吃透
4.熟悉ultraedit
第三课 破解预备知识
一.机械码,又称机器码.
ultraedit打开,编辑exe文件时你会看到
许许多多的由0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F组成的数码,这些数码
就是机器码.
修改程序时必须通过修改机器码来修改exe文件.
二.需要熟练掌握的全部汇编知识(只有这么多)
不大容易理解,可先强行背住,混个脸儿熟,以后慢慢的就理解了
cmp a,b 比较a与b
mov a,b 把b的值送给a
ret 返回主程序
nop 无作用,英文“no operation”的简写,意思是“do nothing”(机器码90)***机器码的含义参看上面
(解释:ultraedit打开编辑exe文件时你看到90,等同于汇编语句nop)
call 调用子程序
je 或jz 若相等则跳(机器码74 或0F84)
jne或jnz 若不相等则跳(机器码75或0F85)
jmp 无条件跳(机器码EB)
jb 若小于则跳
ja 若大于则跳
jg 若大于则跳
jge 若大于等于则跳
jl 若小于则跳
jle 若小于等于则跳
pop 出栈
push 压栈
三.常见修改(机器码)
74=>75 74=>90 74=>EB
75=>74 75=>90 75=>EB
jnz->nop
75->90(相应的机器码修改)
jnz -> jmp
75 -> EB(相应的机器码修改)
jnz -> jz
75->74 (正常) 0F 85 -> 0F 84(特殊情况下,有时,相应的机器码修改)
四.两种不同情况的不同修改方法
1.修改为jmp
je(jne,jz,jnz) =>jmp相应的机器码EB (出错信息向上找到的第一个跳转)jmp的作用是绝对跳,无条件跳,从而跳过下面的出错信息
xxxxxxxxxxxx 出错信息,例如:注册码不对,sorry,未注册版不能...,"Function Not Avaible in Demo" 或 "Command Not Avaible" 或 "Can't save in Shareware/Demo"等 (我们希望把它跳过,不让它出现)
。。。
。。。
xxxxxxxxxxxx 正确路线所在
2.修改为nop
je(jne,jz,jnz) =>nop相应的机器码90 (正确信息向上找到的第一个跳转) nop的作用是抹掉这个跳转,使这个跳转无效,失去作用,从而使程序顺利来到紧跟其后的正确信息处
xxxxxxxxxxxx 正确信息,例如:注册成功,谢谢您的支持等(我们希望它不被跳过,让它出现,程序一定要顺利来到这里)
。。。
。。。
xxxxxxxxxxxx 出错信息(我们希望不要跳到这里,不让它出现)
。。。
。。。
五.爆破无敌口诀 背会此口诀,天下无敌,以后慢慢琢磨,仔细体会,收益多多。如此好的口诀,不要错过
一条(跳)就死,九筒(90)就胡 (对应上面的2.修改为nop)
一条(跳)就胡,一饼(EB)伺候 (对应上面的1.修改为jmp)
妻死(74)便妻无(75)
爸死(84)便爸无(85)
此口诀是我多年经验的积累和提炼,便于大家记忆和教学
六.作业
熟悉ultraedit的使用
第四课 W32DASM介绍
一、静态分析
欲破解一软件,首先应该先用用这个软件,了解一下功能是否有限制,最好阅读一下软件的说明或手册,特别是自己所关心的注册部分的使用说明,这样也许能够找到点线索。
所谓静态分析即从反汇编出来的程序清单上分析。从提示信息入手进行分析.
目前,大多数软件在设计时,都采用了人机对话方式。所谓人机对话,即在软件运行过程中,需要由用户选择的地方,软件即显示相应的提示信息,并等待用户按键选择。而在执行完某一段程序之后,便显示一串提示信息,以反映该段程序运行后的状态,是正常运行,还是出现错误,或者提示用户进行下一步工作的帮助信息。为此,如果我们对静态反汇编出来的程序清单进行阅读,可了解软件的编程思路,以便顺利破解。
人机对话方式给破解带来了方便.
二、W32DASM介绍
crack时常用的静态分析工具是W32DASM.W32DASM目前是8.93版.
大家要用的是W32DASM黄金版中文版,功能强,能完美显示中文
下载 :我主页的破解工具栏目
pw32dasmgold能很方便地反汇编程序,它主要用于静态分析软件,不要用它作动态分析。其使用也很简单,参照后面的范例很快就能掌握。
写破解教程必看------这里只介绍一下如何截取W32DASM部分代码,这样方便写破解心得。
你将鼠标移到W32DASM最左边,点一下,将有一红点出现,再按住shift键,移到你需要的下一行,再按鼠标一下,将选中一段,按CTRL+C复制,CTRL+V粘贴到你的记事本或其它编辑处。
三、 实际修改地址(偏移地址)和行地址(虚拟地址)
pw32dasmgold反汇编出来的代码由三列组成
第一列 行地址(虚拟地址)
第二列 机器码(最终修改时用ultraedit修改)
第三列 汇编指令
第一列 第二列 第三列
:0041BE38 2B45F0 sub eax, dword ptr [ebp-10]
:0041BE3B 6A42 push 00000042
:0041BE3D 50 push eax
:0041BE3E FF75F4 push [ebp-0C]
:0041BE41 FF75F0 push [ebp-10]
:0041BE44 FF35A8AB4400 push dword ptr [0044ABA8]
:0041BE4A FFD7 call edi
:0041BE4C 8345F443 add dword ptr [ebp-0C], 00000043
:0041BE50 391D78AB4400 cmp dword ptr [0044AB78], ebx
:0041BE56 0F84F5000000 je 0041BF51
在W32DASM下将绿色的光条移到某一行代码上 , 在窗口底部可看到
例如@:00461456 @:Offset 00060856h
第一个@指示行地址(虚拟地址),@00461456 与W32DASM光条所在行的第一列相同
第二个@指示实际修改地址(偏移地址) , @Offset 00060856h h表示十六进制
offset的英文意思是偏移
****破解程序的最后一步(注意:修改程序时必须确保程序已脱壳):
用ultraedit找到实际修改地址(偏移地址),修改机器码,从而完成exe文件的修改
方法:打开欲修改的文件,敲入ctrl-g,0x偏移地址(如上面的敲入0x60856),即可到达实际修改地址
四.pw32dasmgold的使用
1."反汇编"菜单下的"打开文件"打开可执行文件,如aa.exe即可
注意:可执行文件不能有壳,切记!!
若有壳,参照第1,2课脱壳
2."参考"菜单中的"串式参考",出现一个新的窗口,使其变小,刚好位于pw32dasmgold主窗口的前面
找到其中的某一条目,双击鼠标左键,你会看到主窗口的绿色光条会移到某一行上
多次反复双击,看绿色光条一共会移到哪几行,有时只有1行,有时有很多行
3.pw32dasmgold只要会用这两个地方就可以了,其他的不用掌握
五.作业
1.熟悉pw32dasmgold
2.熟悉截取W32DASM部分代码 -
教你如何破解PocketPC程序
2007-06-01 01:23:43
教你如何破解PocketPC程序
【文章标题】: 【原创】教你如何破解PocketPC程序
【文章作者】: 大老
【作者邮箱】: dalao@126.com dalao2003_8@hotmail.com
【作者主页】: http://dalao2002.yeah.net
【作者QQ号】: 79234668
【软件名称】: 国产软件省去软件名《XXXX专业版》
【软件介绍】: XXXX专业版,在XXXX原有功能的基础上增加分组/随机铃声/个性振动、来电防火墙、短信拒接来电、个性皮肤/大头贴、通话记录隐形/联系人照片等新功能,分组任你设,规则任你定。拥XXXX,立刻让你的手机成为真正的商务手机!
【下载地址】: http://www.mycnknow.com
【保护方式】: 序列号
【编写语言】: C#.net
【使用工具】: Win2K、IDA pro 4.9 FULL 支持PocketPC调试版 多普达智能手机一部
【操作平台】: PocketPC
【参考文章】:WiNrOOt的编写PPC程序的loader--Intumical1.0126
【文章连接】:
------------------------------------------------------------
http://bbs.pediy.com/showthread. ... aderIntumical1.0126
————————————————————————————----------------------------—————
【作者声明】: 此文献给所有爱好解密的朋友们!
--------------------------------------------------------------------------------
所属组织:=BCG= =[DCG]=
本人作品:
《文件加密狗检测工具 2.1》
《教你如何分析和修改XBOX游戏》
《大老的打狗教程第一篇如何解掉hasp的狗》
《大老的打狗教程第二篇如何解掉深思3的狗》
《大老的打狗教程第三篇(最终篇)如何解掉rockey4的狗》
《Armadill 3.XX 修复导入表加密部分及对应解决方法》
《教你如何破解Gba rom程序》
《深思4 rockey5 rockey6 新一代加密狗乱弹》
===============================================================================
程序是arm指令集的所以,先说一下arm 指令集资料:
===========================================
Arm指令集
(快速查找)
在本文档的汇编语法中,用 # 前缀表示立即值,用 & 表示十六进制值,用 % 表示二进制值,用 {花括号} 表示指令中可选的设置字段或位。下面表格中粗体的指令是核心 ARM 指令,其他的是值得包含的位和片段、移位选项和汇编器助记码(mnemonic)... 还列出了协处理器指令。但是用于 RISC OS 机器的 ARM 处理器不支持协处理器,只在一个可访问的芯片中提供了实际上的协处理器功能。其中包括设置 ARM、cache、MMU 的设施,等...
指令 意义 最早的 CPU / 注释
ADC 带进位的加法 -
ADD 加法 -
AND 逻辑与 -
ASL 算术左移 这是一个选项,不是指令
ASR 算术右移 这是一个选项,不是指令
B 分支 -
BIC 位清除 -
BL 带连接的分支 -
BX 分支到 Thumb 代码 StrongARM SA1110 ?
CDP 协处理器数据操作 -
CMN 比较取负的值 -
CMP 比较值 -
EOR 异或两个值 -
LDC 装载内存到协处理器 -
LDM 装载多个寄存器 -
LDR 装载寄存器 -
LDRB 装载字节到寄存器 -
LDRH 装载半字到寄存器 StrongARM
LDRSB 装载有符号字节到寄存器 StrongARM
LDRSH 装载有符号半字到寄存器 StrongARM
LSL 逻辑左移 这是一个选项,不是指令
LSR 逻辑右移 这是一个选项,不是指令
MCR 协处理器寄存器传送 -
MLA 带累加的乘法 -
MOV 传送值/寄存器到一个寄存器 -
MRC 协处理器寄存器传送 -
MRS 传送状态标志到一个寄存器 ARM 6
MSR 传送一个寄存器的内容到状态标志 ARM 6
MUL 乘法 -
MVN 传送取负的(值) -
ORR 逻辑或 -
ROR 循环右移 这是一个选项,不是指令
RRX 带扩展的循环右移 这是一个选项,不是指令
RSB 反向减法 -
RSC 带借位的反向减法 -
SBC 带借位的减法 -
SMLAL 带累加的有符号长(64 位)乘法 StrongARM
SMULL 有符号长(64 位)乘法 StrongARM
STC 协处理器数据传送 -
STM 存储多个寄存器 -
STR 存储一个寄存器 -
STRB 存储一个字节(从一个寄存器) -
STRH 存储一个半字(从一个寄存器) StrongARM
STRSB 存储一个有符号字节(从一个寄存器) StrongARM
STRSH 存储一个有符号半字(从一个寄存器) StrongARM
SUB 减法 -
SWI 导致一个软件中断 -
SWP 交换寄存器与内存 ARM 3
TEQ 测试等价(概念上的 EOR) -
TST 测试并屏蔽(概念上的 AND) -
UMLAL 带累加的无符号长(64 位)乘法 StrongARM
UMULL 无符号长(64 位)乘法 StrongARM
RISC OS 的 BASIC 汇编器的伪指令
ADR 得到目标的地址(4K 之内)
ADRL 得到目标的地址(超过 4K)
ALIGN 把程序计数器设置到下个字的边界
DCx 定义字节(B)、半字(W)、字(D)、字符串(S)、或浮点(F)值
EQUx 定义字节(B)、半字(W)、字(D)、字符串(S)、或浮点(F)值
OPT 选择汇编选项
===========================================
分析:
这个软件有23天的试用,试用期过后再启动时会出来一个试用期过期的对话框让你输入注册码
先用ida4.9反汇编看看,ida对中文的支持个人感觉还是比较差!查找字符串结果一无所获!
换一个思路!跟踪分析看看!软件有时间限制的话一般都设置在主程序的开始来检测既然这样
就先看看程序的开始,静态分析
============================================================================================================
.text:00059C88 0D C0 A0 E1 MOV R12, SP ; Rd = Op2
.text:00059C8C F0 58 2D E9 STMFD SP!, {R4-R7,R11,R12,LR} ; Store Block to Memory
.text:00059C90 1C B0 8D E2 ADD R11, SP, #0x1C ; Rd = Op1 + Op2
.text:00059C94 04 D0 4D E2 SUB SP, SP, #4 ; Rd = Op1 - Op2
.text:00059C98 00 70 A0 E1 MOV R7, R0 ; Rd = Op2
.text:00059C9C 01 60 A0 E1 MOV R6, R1 ; Rd = Op2
.text:00059CA0 02 50 A0 E1 MOV R5, R2 ; Rd = Op2
.text:00059CA4 03 40 A0 E1 MOV R4, R3 ; Rd = Op2
.text:00059CA8 41 00 00 EB BL _cinit ; Branch with Link
.text:00059CA8
.text:00059CAC 04 30 A0 E1 MOV R3, R4 ; nShowCmd
.text:00059CB0 05 20 A0 E1 MOV R2, R5 ; lpCmdLine
.text:00059CB4 06 10 A0 E1 MOV R1, R6 ; hPrevInstance
.text:00059CB8 07 00 A0 E1 MOV R0, R7 ; hInstance
.text:00059CBC A4 C8 FF EB BL WinMain ; Branch with Link =====》c程序的主入口
.text:00059CBC
.text:00059CC0 00 40 A0 E1 MOV R4, R0 ; Rd = Op2
.text:00059CC4 20 40 0B E5 STR R4, [R11,#var_20] ; Store to Memory
.text:00059CC8 01 00 00 EA B loc_59CD4 ; Branch
.text:00
==============================================================================================================
进入程序主入口后开始用ida的动态调试用f2设置断点继续跟踪
.text:0004BF58 CC C1 9F E5 LDR R12, =0xFFFFFB54 ; Load from Memory
.text:0004BF5C 0C D0 8D E0 ADD SP, SP, R12 ; Rd = Op1 + Op2
.text:0004BF60 00 40 A0 E1 MOV R4, R0 ; Rd = Op2
.text:0004BF64 02 50 A0 E1 MOV R5, R2 ; Rd = Op2
.text:0004BF68 08 00 A0 E3 MOV R0, #8 ; Rd = Op2
.text:0004BF6C 11 1E A0 E3 MOV R1, #0x110 ; Rd = Op2
.text:0004BF70 28 00 8D E5 STR R0, [SP,#0x4C4+var_49C] ; Store to Memory
.text:0004BF74 28 00 8D E2 ADD R0, SP, #0x4C4+var_49C ; LPINITCOMMONCONTROLSEX
.text:0004BF78 2C 10 8D E5 STR R1, [SP,#0x4C4+var_49C.dwICC] ; Store to Memory
.text:0004BF7C E5 37 00 EB BL InitCommonControlsEx ; Branch with Link
.text:0004BF7C
.text:0004BF80 00 10 A0 E3 MOV R1, #0 ; dwCoInit
.text:0004BF84 00 00 A0 E3 MOV R0, #0 ; pvReserved
.text:0004BF88 DC 37 00 EB BL CoInitializeEx ; Branch with Link ==>初始化函数
.text:0004BF88
.text:0004BF8C 94 71 9F E5 LDR R7, =unk_62B88 ; Load from Memory
.text:0004BF90 00 30 A0 E3 MOV R3, #0 ; Rd = Op2
.text:0004BF94 04 20 A0 E1 MOV R2, R4 ; Rd = Op2
.text:0004BF98 00 10 A0 E3 MOV R1, #0 ; Rd = Op2
.text:0004BF9C 07 00 A0 E1 MOV R0, R7 ; Rd = Op2
.text:0004BFA0 5E 01 00 EB BL sub_4C520 ; Branch with Link
.text:0004BFA0
.text:0004BFA4 78 01 9F E5 LDR R0, =aCallhistory ; wchar_t *
.text:0004BFA8 05 10 A0 E1 MOV R1, R5 ; wchar_t *
.text:0004BFAC 04 40 87 E5 STR R4, [R7,#4] ; Store to Memory
.text:0004BFB0 9A 38 00 EB BL _wcsicmp ; Branch with Link
.text:0004BFB0
.text:0004BFB4 64 41 9F E5 LDR R4, =off_61A94 ; Load from Memory
.text:0004BFB8 01 60 A0 E3 MOV R6, #1 ; Rd = Op2
.text:0004BFBC 00 00 50 E3 CMP R0, #0 ; Set cond. codes on Op1 - Op2
.text:0004BFC0 00 00 94 E5 LDR R0, [R4] ; Load from Memory
.text:0004BFC4 00 80 A0 E3 MOV R8, #0 ; Rd = Op2
.text:0004BFC8 06 50 A0 E1 MOV R5, R6 ; Rd = Op2
.text:0004BFCC 08 50 A0 11 MOVNE R5, R8 ; Rd = Op2
.text:0004BFD0 05 30 A0 E1 MOV R3, R5 ; Rd = Op2
.text:0004BFD4 10 20 8D E2 ADD R2, SP, #0x4C4+var_4B4 ; Rd = Op1 + Op2
.text:0004BFD8 00 10 A0 E3 MOV R1, #0 ; Rd = Op2
.text:0004BFDC 7C FF FF EB BL sub_4BDD4 =====》发现过这个call后就会出现过期对话框
.text:0004BFDC
.text:0004BFE0 00 00 50 E3 CMP R0, #0 ; Set cond. codes on Op1 - Op2
.text:0004BFE4 40 00 00 4A BMI loc_4C0EC ; Branch
.text:0004BFE4
.text:0004BFE8 10 00 9D E5 LDR R0, [SP,#0x4C4+var_4B4] ; Load from Memory
.text:0004BFEC 00 00 50 E3 CMP R0, #0 ; Set cond. codes on Op1 - Op2
.text:0004BFF0 3D 00 00 1A BNE loc_4C0EC ; Branch
.text:0004BFF0
===================================================
重新进入后继续分析
.text:0004BDD8 SUB SP, SP, #0x64
.text:0004BDDC MOV R5, R0
.text:0004BDE0 MOV R6, R1
.text:0004BDE4 MOV R8, R2
.text:0004BDE8 MOV R7, R3
.text:0004BDEC LDR R4, =unk_62C2C
.text:0004BDF0 MOV R10, #0
.text:0004BDF4 STR R10, [R8]
.text:0004BDF8 MOV R9, #5
.text:0004BDFC
.text:0004BDFC loc_4BDFC ; CODE XREF: sub_4BDD4+88j
.text:0004BDFC MOV R2, R5 ; lpName
.text:0004BE00 MOV R1, #0 ; bInitialOwner
.text:0004BE04 MOV R0, #0 ; lpsa
.text:0004BE08 BL CreateMutexW
.text:0004BE08
.text:0004BE0C CMP R0, #0
.text:0004BE10 STR R0, [R4]
.text:0004BE14 BEQ loc_4BF28
.text:0004BE14
.text:0004BE18 BL GetLastError
.text:0004BE18
.text:0004BE1C CMP R0, #0xB7
.text:0004BE20 BNE loc_4BE8C
.text:0004BE20
.text:0004BE24 MOV R1, R6 ; lpWindowName
.text:0004BE28 MOV R0, R5 ; lpClassName
.text:0004BE2C BL FindWindowW
.text:0004BE2C
.text:0004BE30 CMP R0, #0
.text:0004BE34 BNE loc_4BE6C
.text:0004BE34
.text:0004BE38 MOV R0, #0x1F4 ; dwMilliseconds
.text:0004BE3C BL Sleep
.text:0004BE3C
.text:0004BE40 MOV R1, R6 ; lpWindowName
.text:0004BE44 MOV R0, R5 ; lpClassName
.text:0004BE48 BL FindWindowW
.text:0004BE48
.text:0004BE4C CMP R0, #0
.text:0004BE50 BNE loc_4BE6C========》上面的代码是查找看看是否程序已经运行
.text:0004BE50
.text:0004BE54 SUB R9, R9, #1
.text:0004BE58 CMP R9, #0
.text:0004BE5C BGT loc_4BDFC
.text:0004BE5C
.text:0004BE60 LDR R0, =unk_80004005
.text:0004BE64 ADD SP, SP, #0x64
.text:0004BE68 LDMFD SP!, {R4-R10,PC}
.text:0004BE68
.text:0004BE6C ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0004BE6C
.text:0004BE6C loc_4BE6C ; CODE XREF: sub_4BDD4+60j
.text:0004BE6C ; sub_4BDD4+7Cj
.text:0004BE6C MOV R1, #0x400
.text:0004BE70 MOV R3, #0 ; lParam
.text:0004BE74 MOV R2, R7 ; wParam
.text:0004BE78 ORR R1, R1, #0xB ; Msg
.text:0004BE7C BL PostMessageW
.text:0004BE7C
.text:0004BE80 MOV R3, #1
.text:0004BE84 STR R3, [R8]
.text:0004BE88 B loc_4BF20
.text:0004BE88
.text:0004BE8C ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0004BE8C
.text:0004BE8C loc_4BE8C ; CODE XREF: sub_4BDD4+4Cj
.text:0004BE8C BL sub_30A28 ====》注意这个call(1)
.text:0004BE8C
.text:0004BE90 CMP R0, #0
.text:0004BE94 BEQ loc_4BEB4
.text:0004BE94
.text:0004BE98 LDR R1, =unk_62C0C
.text:0004BE9C MOVL R2, 0xFFFFFFFF
.text:0004BEA0 ADD R0, R1, #0x1C
.text:0004BEA4
.text:0004BEA4 loc_4BEA4 ; CODE XREF: sub_4BDD4+D8j
.text:0004BEA4 STR R2, [R1],#4
.text:0004BEA8 CMP R1, R0
.text:0004BEAC BNE loc_4BEA4
.text:0004BEAC
.text:0004BEB0 B loc_4BF20
.text:0004BEB0
.text:0004BEB4 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0004BEB4
.text:0004BEB4 loc_4BEB4 ; CODE XREF: sub_4BDD4+C0j
.text:0004BEB4 BL sub_4C1D0 =======>还有这个call的返回值
.text:0004BEB4
.text:0004BEB8 LDR R1, =unk_62C0C
.text:0004BEBC MOV R3, R0=====> 返回值传给r3寄存器
.text:0004BEC0 ADD R0, R1, #0x1C
.text:0004BEC4
.text:0004BEC4 loc_4BEC4 ; CODE XREF: sub_4BDD4+F8j
.text:0004BEC4 STR R3, [R1],#4
.text:0004BEC8 CMP R1, R0
.text:0004BECC BNE loc_4BEC4
.text:0004BECC
.text:0004BED0 CMP R3, #0==========>这里判断是否为0如果是则表示程序过期
.text:0004BED4 BNE loc_4BF20===》这是个关键跳转过期则不跳下面的代码是显示过期对话框的
.text:0004BED4
.text:0004BED8 ADD R0, SP, #0x84+var_84
.text:0004BEDC BL sub_3A770
.text:0004BEDC
.text:0004BEE0 ADD R0, SP, #0x84+var_5C
.text:0004BEE4 BL sub_3E0BC
.text:0004BEE4
.text:0004BEE8 LDR R3, =off_5B40C
.text:0004BEEC LDR R0, =off_5B404
.text:0004BEF0 STR R3, [SP,#0x84+var_84]
.text:0004BEF4 STR R0, [SP,#0x84+var_5C]
.text:0004BEF8 BL GetActiveWindow
.text:0004BEF8
.text:0004BEFC MOV R1, R0
.text:0004BF00 MOV R2, #0
.text:0004BF04 ADD R0, SP, #0x84+var_84
.text:0004BF08 BL sub_3E054
.text:0004BF08
.text:0004BF0C CMN R0, #1
.text:0004BF10 BNE loc_4BF18
========================================================
.text:0004BEB4地址的日期判断分析
========================================================
.text:0004C1D4 SUB SP, SP, #0x44 ; lpData
.text:0004C1D8 LDR R4, =aSoftwareMicros
.text:0004C1DC ADD R0, SP, #0x58+hKey
.text:0004C1E0 MOV R3, #sub_20000
.text:0004C1E4 STR R0, [SP,#0x58+lpData]
.text:0004C1E8 MOV R7, #0
.text:0004C1EC ORR R3, R3, #0x19 ; samDesired
.text:0004C1F0 STR R7, [SP,#0x58+hKey]
.text:0004C1F4 MOV R2, #0 ; ulOptions
.text:0004C1F8 MOV R1, R4 ; lpSubKey
.text:0004C1FC MOV R0, #0x80000001 ; hKey
.text:0004C200 BL RegOpenKeyExW
.text:0004C200
.text:0004C204 CMP R0, #0
.text:0004C208 BNE loc_4C34C
.text:0004C208
.text:0004C20C ADD R0, SP, #0x58+var_40
.text:0004C210 LDR R5, =aProxySharpv1_9
.text:0004C214 ADD R1, SP, #0x58+var_34
.text:0004C218 STR R0, [SP,#0x58+cbData]
.text:0004C21C STR R1, [SP,#0x58+lpData]
.text:0004C220 MOV R6, #0x10
.text:0004C224 LDR R0, [SP,#0x58+hKey] ; hKey
.text:0004C228 ADD R3, SP, #0x58+Type ; lpType
.text:0004C22C MOV R2, #0 ; lpReserved
.text:0004C230 STR R6, [SP,#0x58+var_40]
.text:0004C234 MOV R1, R5 ; lpValueName
.text:0004C238 BL RegQueryValueExW
.text:0004C238
.text:0004C23C CMP R0, #0
.text:0004C240 BNE loc_4C2CC
.text:0004C240
.text:0004C244 ADD R0, SP, #0x58+SystemTime ; lpSystemTime
.text:0004C248 BL GetLocalTime=========》取本地时间
.text:0004C248
.text:0004C24C LDRH R0, [SP,#0x58+SystemTime]
.text:0004C250 LDRH R3, [SP,#0x58+var_34]
.text:0004C254 MOV R0, R0,LSL#16
.text:0004C258 LDRH R5, [SP,#0x58+SystemTime.wMonth]===》取月
.text:0004C25C MOV R1, R0,LSR#16
.text:0004C260 LDRH R6, [SP,#0x58+var_34+2]
.text:0004C264 MOV R2, R3,LSL#16
.text:0004C268 MOV R0, #0x16C
.text:0004C26C SUB R2, R1, R2,LSR#16
.text:0004C270 ORR R0, R0, #1
.text:0004C274 MUL R4, R2, R0
.text:0004C278 MOV R0, R5,LSL#16
.text:0004C27C MOV R1, R0,LSR#16
.text:0004C280 MOV R3, R6,LSL#16
.text:0004C284 SUB R2, R1, R3,LSR#16
.text:0004C288 MOV R0, #0x1E
.text:0004C28C MLA R3, R2, R0, R4
.text:0004C290 LDRH R0, [SP,#0x58+var_2E]
.text:0004C294 MOV R1, R0,LSL#16
.text:0004C298 LDRH R0, [SP,#0x58+SystemTime.wDay]取天
.text:0004C29C SUB R2, R3, R1,LSR#16
.text:0004C2A0 MOV R1, R0,LSL#16
.text:0004C2A4 ADDS R3, R2, R1,LSR#16
.text:0004C2A8 BMI loc_4C338
.text:0004C2A8
.text:0004C2AC CMP R3, #0x17 ===》r3是已用天数和23比较看看是不是过期
.text:0004C2B0 BGE loc_4C338
.text:0004C2B0
.text:0004C2B4 LDR R0, [SP,#0x58+hKey] ; hKey
.text:0004C2B8 RSB R7, R3, #0x17
.text:0004C2BC BL RegCloseKey
.text:0004C2BC
.text:0004C2C0 MOV R0, R7
.text:0004C2C4 ADD SP, SP, #0x44
.text:0004C2C8 LDMFD SP!, {R4-R7,PC} ; lpData
.text:0004C2C8
.text:0004C2CC ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0004C2CC
.text:0004C2CC loc_4C2CC ; CODE XREF: sub_4C1D0+70j
.text:0004C2CC ADD R0, SP, #0x58+var_34 ; lpSystemTime
.text:0004C2D0 BL GetLocalTime
.text:0004C2D0
.text:0004C2D4 STR R7, [SP,#0x58+lpSecurityAttributes]
.text:0004C2D8 ADD R3, SP, #0x58+var_38
.text:0004C2DC STR R7, [SP,#0x58+cbData]
.text:0004C2E0 ADD R0, SP, #0x58+hKey
.text:0004C2E4 STR R3, [SP,#0x58+lpdwDisposition]
.text:0004C2E8 STR R0, [SP,#0x58+phkResult]
.text:0004C2EC MOV R3, #0 ; lpClass
.text:0004C2F0 MOV R2, #0 ; Reserved
.text:0004C2F4 STR R7, [SP,#0x58+lpData]
.text:0004C2F8 MOV R1, R4 ; lpSubKey
.text:0004C2FC MOV R0, #0x80000001 ; hKey
.text:0004C300 BL RegCreateKeyExW=====》建立一个新的注册表键值
.text:0004C300
.text:0004C304 CMP R0, #0
.text:0004C308 MOVNE R0, #0x17
.text:0004C30C ADDNE SP, SP, #0x44
.text:0004C310 LDMNEFD SP!, {R4-R7,PC}
.text:0004C314 STR R6, [SP,#0x58+cbData]
.text:0004C318 ADD R0, SP, #0x58+var_34
.text:0004C31C STR R0, [SP,#0x58+lpData]
.text:0004C320 MOV R3, #3 ; dwType
.text:0004C324 MOV R2, #0 ; Reserved
.text:0004C328 MOV R1, R5 ; lpValueName
.text:0004C32C LDR R0, [SP,#0x58+hKey] ; hKey
.text:0004C330 BL RegSetValueExW =====》写入注册表键值,这部分是处理第一次试用建立的日期时间
.text:0004C330
.text:0004C334 MOV R7, #0x17
.text:0004C338
.text:0004C338 loc_4C338 ; CODE XREF: sub_4C1D0+D8j
.text:0004C338 ; sub_4C1D0+E0j
.text:0004C338 LDR R0, [SP,#0x58+hKey] ; hKey
.text:0004C33C BL RegCloseKey
.text:0004C33C
.text:0004C340 MOV R0, R7
.text:0004C344 ADD SP, SP, #0x44
.text:0004C348 LDMFD SP!, {R4-R7,PC}
.text:0004C348
.text:0004C34C ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0004C34C
.text:0004C34C loc_4C34C ; CODE XREF: sub_4C1D0+38j
.text:0004C34C LDR R7, [SP,#0x58+var_38]
.text:0004C350 MOV R0, R7
.text:0004C354 ADD SP, SP, #0x44
.text:0004C358 LDMFD SP!, {R4-R7,P
========================================================
--------------------------------------------------------------------------------
【经验总结】
经过分析发现.text:0004BEB4是日期判断的关键改法有很多!比较好的一个改发就是
改0004C240 BNE loc_4C2CC========》BAL loc_4C2CC即可去处日期限制!
用winhex改完存盘测试ok!这个程序是我破解的第一个ppc程序总体感觉ppc的程序只要有毅力和耐心还是比较容易破解的!
如果用ida想调试ppc程序的话必须有有一台智能手机pda,没有手机听说可以用模拟器来调试!其实这个
程序还有可以再解的完美些!注意.text:0004BE8C(1)处的call经过分析发现这个call是注册码验证的call,我是赖的分
析了
有兴趣的朋友可以自己研究!再次感谢你耐心的看完这篇文章,希望对想研究PocketPC破解的初学者有所帮助!
--------------------------------------------------------------------------------
【版权声明】: 本文原创于大老主页, 转载请注明作者并保持文章的完整, 谢谢!
2006年07月09日 凌晨02:59:20
加密狗杀狗专业户!
http://dalao2002.yeah.net -
教你如何破解PocketPC程序
2007-06-01 01:23:43
教你如何破解PocketPC程序
【文章标题】: 【原创】教你如何破解PocketPC程序
【文章作者】: 大老
【作者邮箱】: dalao@126.com dalao2003_8@hotmail.com
【作者主页】: http://dalao2002.yeah.net
【作者QQ号】: 79234668
【软件名称】: 国产软件省去软件名《XXXX专业版》
【软件介绍】: XXXX专业版,在XXXX原有功能的基础上增加分组/随机铃声/个性振动、来电防火墙、短信拒接来电、个性皮肤/大头贴、通话记录隐形/联系人照片等新功能,分组任你设,规则任你定。拥XXXX,立刻让你的手机成为真正的商务手机!
【下载地址】: http://www.mycnknow.com
【保护方式】: 序列号
【编写语言】: C#.net
【使用工具】: Win2K、IDA pro 4.9 FULL 支持PocketPC调试版 多普达智能手机一部
【操作平台】: PocketPC
【参考文章】:WiNrOOt的编写PPC程序的loader--Intumical1.0126
【文章连接】:
------------------------------------------------------------
http://bbs.pediy.com/showthread. ... aderIntumical1.0126
————————————————————————————----------------------------—————
【作者声明】: 此文献给所有爱好解密的朋友们!
--------------------------------------------------------------------------------
所属组织:=BCG= =[DCG]=
本人作品:
《文件加密狗检测工具 2.1》
《教你如何分析和修改XBOX游戏》
《大老的打狗教程第一篇如何解掉hasp的狗》
《大老的打狗教程第二篇如何解掉深思3的狗》
《大老的打狗教程第三篇(最终篇)如何解掉rockey4的狗》
《Armadill 3.XX 修复导入表加密部分及对应解决方法》
《教你如何破解Gba rom程序》
《深思4 rockey5 rockey6 新一代加密狗乱弹》
===============================================================================
程序是arm指令集的所以,先说一下arm 指令集资料:
===========================================
Arm指令集
(快速查找)
在本文档的汇编语法中,用 # 前缀表示立即值,用 & 表示十六进制值,用 % 表示二进制值,用 {花括号} 表示指令中可选的设置字段或位。下面表格中粗体的指令是核心 ARM 指令,其他的是值得包含的位和片段、移位选项和汇编器助记码(mnemonic)... 还列出了协处理器指令。但是用于 RISC OS 机器的 ARM 处理器不支持协处理器,只在一个可访问的芯片中提供了实际上的协处理器功能。其中包括设置 ARM、cache、MMU 的设施,等...
指令 意义 最早的 CPU / 注释
ADC 带进位的加法 -
ADD 加法 -
AND 逻辑与 -
ASL 算术左移 这是一个选项,不是指令
ASR 算术右移 这是一个选项,不是指令
B 分支 -
BIC 位清除 -
BL 带连接的分支 -
BX 分支到 Thumb 代码 StrongARM SA1110 ?
CDP 协处理器数据操作 -
CMN 比较取负的值 -
CMP 比较值 -
EOR 异或两个值 -
LDC 装载内存到协处理器 -
LDM 装载多个寄存器 -
LDR 装载寄存器 -
LDRB 装载字节到寄存器 -
LDRH 装载半字到寄存器 StrongARM
LDRSB 装载有符号字节到寄存器 StrongARM
LDRSH 装载有符号半字到寄存器 StrongARM
LSL 逻辑左移 这是一个选项,不是指令
LSR 逻辑右移 这是一个选项,不是指令
MCR 协处理器寄存器传送 -
MLA 带累加的乘法 -
MOV 传送值/寄存器到一个寄存器 -
MRC 协处理器寄存器传送 -
MRS 传送状态标志到一个寄存器 ARM 6
MSR 传送一个寄存器的内容到状态标志 ARM 6
MUL 乘法 -
MVN 传送取负的(值) -
ORR 逻辑或 -
ROR 循环右移 这是一个选项,不是指令
RRX 带扩展的循环右移 这是一个选项,不是指令
RSB 反向减法 -
RSC 带借位的反向减法 -
SBC 带借位的减法 -
SMLAL 带累加的有符号长(64 位)乘法 StrongARM
SMULL 有符号长(64 位)乘法 StrongARM
STC 协处理器数据传送 -
STM 存储多个寄存器 -
STR 存储一个寄存器 -
STRB 存储一个字节(从一个寄存器) -
STRH 存储一个半字(从一个寄存器) StrongARM
STRSB 存储一个有符号字节(从一个寄存器) StrongARM
STRSH 存储一个有符号半字(从一个寄存器) StrongARM
SUB 减法 -
SWI 导致一个软件中断 -
SWP 交换寄存器与内存 ARM 3
TEQ 测试等价(概念上的 EOR) -
TST 测试并屏蔽(概念上的 AND) -
UMLAL 带累加的无符号长(64 位)乘法 StrongARM
UMULL 无符号长(64 位)乘法 StrongARM
RISC OS 的 BASIC 汇编器的伪指令
ADR 得到目标的地址(4K 之内)
ADRL 得到目标的地址(超过 4K)
ALIGN 把程序计数器设置到下个字的边界
DCx 定义字节(B)、半字(W)、字(D)、字符串(S)、或浮点(F)值
EQUx 定义字节(B)、半字(W)、字(D)、字符串(S)、或浮点(F)值
OPT 选择汇编选项
===========================================
分析:
这个软件有23天的试用,试用期过后再启动时会出来一个试用期过期的对话框让你输入注册码
先用ida4.9反汇编看看,ida对中文的支持个人感觉还是比较差!查找字符串结果一无所获!
换一个思路!跟踪分析看看!软件有时间限制的话一般都设置在主程序的开始来检测既然这样
就先看看程序的开始,静态分析
============================================================================================================
.text:00059C88 0D C0 A0 E1 MOV R12, SP ; Rd = Op2
.text:00059C8C F0 58 2D E9 STMFD SP!, {R4-R7,R11,R12,LR} ; Store Block to Memory
.text:00059C90 1C B0 8D E2 ADD R11, SP, #0x1C ; Rd = Op1 + Op2
.text:00059C94 04 D0 4D E2 SUB SP, SP, #4 ; Rd = Op1 - Op2
.text:00059C98 00 70 A0 E1 MOV R7, R0 ; Rd = Op2
.text:00059C9C 01 60 A0 E1 MOV R6, R1 ; Rd = Op2
.text:00059CA0 02 50 A0 E1 MOV R5, R2 ; Rd = Op2
.text:00059CA4 03 40 A0 E1 MOV R4, R3 ; Rd = Op2
.text:00059CA8 41 00 00 EB BL _cinit ; Branch with Link
.text:00059CA8
.text:00059CAC 04 30 A0 E1 MOV R3, R4 ; nShowCmd
.text:00059CB0 05 20 A0 E1 MOV R2, R5 ; lpCmdLine
.text:00059CB4 06 10 A0 E1 MOV R1, R6 ; hPrevInstance
.text:00059CB8 07 00 A0 E1 MOV R0, R7 ; hInstance
.text:00059CBC A4 C8 FF EB BL WinMain ; Branch with Link =====》c程序的主入口
.text:00059CBC
.text:00059CC0 00 40 A0 E1 MOV R4, R0 ; Rd = Op2
.text:00059CC4 20 40 0B E5 STR R4, [R11,#var_20] ; Store to Memory
.text:00059CC8 01 00 00 EA B loc_59CD4 ; Branch
.text:00
==============================================================================================================
进入程序主入口后开始用ida的动态调试用f2设置断点继续跟踪
.text:0004BF58 CC C1 9F E5 LDR R12, =0xFFFFFB54 ; Load from Memory
.text:0004BF5C 0C D0 8D E0 ADD SP, SP, R12 ; Rd = Op1 + Op2
.text:0004BF60 00 40 A0 E1 MOV R4, R0 ; Rd = Op2
.text:0004BF64 02 50 A0 E1 MOV R5, R2 ; Rd = Op2
.text:0004BF68 08 00 A0 E3 MOV R0, #8 ; Rd = Op2
.text:0004BF6C 11 1E A0 E3 MOV R1, #0x110 ; Rd = Op2
.text:0004BF70 28 00 8D E5 STR R0, [SP,#0x4C4+var_49C] ; Store to Memory
.text:0004BF74 28 00 8D E2 ADD R0, SP, #0x4C4+var_49C ; LPINITCOMMONCONTROLSEX
.text:0004BF78 2C 10 8D E5 STR R1, [SP,#0x4C4+var_49C.dwICC] ; Store to Memory
.text:0004BF7C E5 37 00 EB BL InitCommonControlsEx ; Branch with Link
.text:0004BF7C
.text:0004BF80 00 10 A0 E3 MOV R1, #0 ; dwCoInit
.text:0004BF84 00 00 A0 E3 MOV R0, #0 ; pvReserved
.text:0004BF88 DC 37 00 EB BL CoInitializeEx ; Branch with Link ==>初始化函数
.text:0004BF88
.text:0004BF8C 94 71 9F E5 LDR R7, =unk_62B88 ; Load from Memory
.text:0004BF90 00 30 A0 E3 MOV R3, #0 ; Rd = Op2
.text:0004BF94 04 20 A0 E1 MOV R2, R4 ; Rd = Op2
.text:0004BF98 00 10 A0 E3 MOV R1, #0 ; Rd = Op2
.text:0004BF9C 07 00 A0 E1 MOV R0, R7 ; Rd = Op2
.text:0004BFA0 5E 01 00 EB BL sub_4C520 ; Branch with Link
.text:0004BFA0
.text:0004BFA4 78 01 9F E5 LDR R0, =aCallhistory ; wchar_t *
.text:0004BFA8 05 10 A0 E1 MOV R1, R5 ; wchar_t *
.text:0004BFAC 04 40 87 E5 STR R4, [R7,#4] ; Store to Memory
.text:0004BFB0 9A 38 00 EB BL _wcsicmp ; Branch with Link
.text:0004BFB0
.text:0004BFB4 64 41 9F E5 LDR R4, =off_61A94 ; Load from Memory
.text:0004BFB8 01 60 A0 E3 MOV R6, #1 ; Rd = Op2
.text:0004BFBC 00 00 50 E3 CMP R0, #0 ; Set cond. codes on Op1 - Op2
.text:0004BFC0 00 00 94 E5 LDR R0, [R4] ; Load from Memory
.text:0004BFC4 00 80 A0 E3 MOV R8, #0 ; Rd = Op2
.text:0004BFC8 06 50 A0 E1 MOV R5, R6 ; Rd = Op2
.text:0004BFCC 08 50 A0 11 MOVNE R5, R8 ; Rd = Op2
.text:0004BFD0 05 30 A0 E1 MOV R3, R5 ; Rd = Op2
.text:0004BFD4 10 20 8D E2 ADD R2, SP, #0x4C4+var_4B4 ; Rd = Op1 + Op2
.text:0004BFD8 00 10 A0 E3 MOV R1, #0 ; Rd = Op2
.text:0004BFDC 7C FF FF EB BL sub_4BDD4 =====》发现过这个call后就会出现过期对话框
.text:0004BFDC
.text:0004BFE0 00 00 50 E3 CMP R0, #0 ; Set cond. codes on Op1 - Op2
.text:0004BFE4 40 00 00 4A BMI loc_4C0EC ; Branch
.text:0004BFE4
.text:0004BFE8 10 00 9D E5 LDR R0, [SP,#0x4C4+var_4B4] ; Load from Memory
.text:0004BFEC 00 00 50 E3 CMP R0, #0 ; Set cond. codes on Op1 - Op2
.text:0004BFF0 3D 00 00 1A BNE loc_4C0EC ; Branch
.text:0004BFF0
===================================================
重新进入后继续分析
.text:0004BDD8 SUB SP, SP, #0x64
.text:0004BDDC MOV R5, R0
.text:0004BDE0 MOV R6, R1
.text:0004BDE4 MOV R8, R2
.text:0004BDE8 MOV R7, R3
.text:0004BDEC LDR R4, =unk_62C2C
.text:0004BDF0 MOV R10, #0
.text:0004BDF4 STR R10, [R8]
.text:0004BDF8 MOV R9, #5
.text:0004BDFC
.text:0004BDFC loc_4BDFC ; CODE XREF: sub_4BDD4+88j
.text:0004BDFC MOV R2, R5 ; lpName
.text:0004BE00 MOV R1, #0 ; bInitialOwner
.text:0004BE04 MOV R0, #0 ; lpsa
.text:0004BE08 BL CreateMutexW
.text:0004BE08
.text:0004BE0C CMP R0, #0
.text:0004BE10 STR R0, [R4]
.text:0004BE14 BEQ loc_4BF28
.text:0004BE14
.text:0004BE18 BL GetLastError
.text:0004BE18
.text:0004BE1C CMP R0, #0xB7
.text:0004BE20 BNE loc_4BE8C
.text:0004BE20
.text:0004BE24 MOV R1, R6 ; lpWindowName
.text:0004BE28 MOV R0, R5 ; lpClassName
.text:0004BE2C BL FindWindowW
.text:0004BE2C
.text:0004BE30 CMP R0, #0
.text:0004BE34 BNE loc_4BE6C
.text:0004BE34
.text:0004BE38 MOV R0, #0x1F4 ; dwMilliseconds
.text:0004BE3C BL Sleep
.text:0004BE3C
.text:0004BE40 MOV R1, R6 ; lpWindowName
.text:0004BE44 MOV R0, R5 ; lpClassName
.text:0004BE48 BL FindWindowW
.text:0004BE48
.text:0004BE4C CMP R0, #0
.text:0004BE50 BNE loc_4BE6C========》上面的代码是查找看看是否程序已经运行
.text:0004BE50
.text:0004BE54 SUB R9, R9, #1
.text:0004BE58 CMP R9, #0
.text:0004BE5C BGT loc_4BDFC
.text:0004BE5C
.text:0004BE60 LDR R0, =unk_80004005
.text:0004BE64 ADD SP, SP, #0x64
.text:0004BE68 LDMFD SP!, {R4-R10,PC}
.text:0004BE68
.text:0004BE6C ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0004BE6C
.text:0004BE6C loc_4BE6C ; CODE XREF: sub_4BDD4+60j
.text:0004BE6C ; sub_4BDD4+7Cj
.text:0004BE6C MOV R1, #0x400
.text:0004BE70 MOV R3, #0 ; lParam
.text:0004BE74 MOV R2, R7 ; wParam
.text:0004BE78 ORR R1, R1, #0xB ; Msg
.text:0004BE7C BL PostMessageW
.text:0004BE7C
.text:0004BE80 MOV R3, #1
.text:0004BE84 STR R3, [R8]
.text:0004BE88 B loc_4BF20
.text:0004BE88
.text:0004BE8C ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0004BE8C
.text:0004BE8C loc_4BE8C ; CODE XREF: sub_4BDD4+4Cj
.text:0004BE8C BL sub_30A28 ====》注意这个call(1)
.text:0004BE8C
.text:0004BE90 CMP R0, #0
.text:0004BE94 BEQ loc_4BEB4
.text:0004BE94
.text:0004BE98 LDR R1, =unk_62C0C
.text:0004BE9C MOVL R2, 0xFFFFFFFF
.text:0004BEA0 ADD R0, R1, #0x1C
.text:0004BEA4
.text:0004BEA4 loc_4BEA4 ; CODE XREF: sub_4BDD4+D8j
.text:0004BEA4 STR R2, [R1],#4
.text:0004BEA8 CMP R1, R0
.text:0004BEAC BNE loc_4BEA4
.text:0004BEAC
.text:0004BEB0 B loc_4BF20
.text:0004BEB0
.text:0004BEB4 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0004BEB4
.text:0004BEB4 loc_4BEB4 ; CODE XREF: sub_4BDD4+C0j
.text:0004BEB4 BL sub_4C1D0 =======>还有这个call的返回值
.text:0004BEB4
.text:0004BEB8 LDR R1, =unk_62C0C
.text:0004BEBC MOV R3, R0=====> 返回值传给r3寄存器
.text:0004BEC0 ADD R0, R1, #0x1C
.text:0004BEC4
.text:0004BEC4 loc_4BEC4 ; CODE XREF: sub_4BDD4+F8j
.text:0004BEC4 STR R3, [R1],#4
.text:0004BEC8 CMP R1, R0
.text:0004BECC BNE loc_4BEC4
.text:0004BECC
.text:0004BED0 CMP R3, #0==========>这里判断是否为0如果是则表示程序过期
.text:0004BED4 BNE loc_4BF20===》这是个关键跳转过期则不跳下面的代码是显示过期对话框的
.text:0004BED4
.text:0004BED8 ADD R0, SP, #0x84+var_84
.text:0004BEDC BL sub_3A770
.text:0004BEDC
.text:0004BEE0 ADD R0, SP, #0x84+var_5C
.text:0004BEE4 BL sub_3E0BC
.text:0004BEE4
.text:0004BEE8 LDR R3, =off_5B40C
.text:0004BEEC LDR R0, =off_5B404
.text:0004BEF0 STR R3, [SP,#0x84+var_84]
.text:0004BEF4 STR R0, [SP,#0x84+var_5C]
.text:0004BEF8 BL GetActiveWindow
.text:0004BEF8
.text:0004BEFC MOV R1, R0
.text:0004BF00 MOV R2, #0
.text:0004BF04 ADD R0, SP, #0x84+var_84
.text:0004BF08 BL sub_3E054
.text:0004BF08
.text:0004BF0C CMN R0, #1
.text:0004BF10 BNE loc_4BF18
========================================================
.text:0004BEB4地址的日期判断分析
========================================================
.text:0004C1D4 SUB SP, SP, #0x44 ; lpData
.text:0004C1D8 LDR R4, =aSoftwareMicros
.text:0004C1DC ADD R0, SP, #0x58+hKey
.text:0004C1E0 MOV R3, #sub_20000
.text:0004C1E4 STR R0, [SP,#0x58+lpData]
.text:0004C1E8 MOV R7, #0
.text:0004C1EC ORR R3, R3, #0x19 ; samDesired
.text:0004C1F0 STR R7, [SP,#0x58+hKey]
.text:0004C1F4 MOV R2, #0 ; ulOptions
.text:0004C1F8 MOV R1, R4 ; lpSubKey
.text:0004C1FC MOV R0, #0x80000001 ; hKey
.text:0004C200 BL RegOpenKeyExW
.text:0004C200
.text:0004C204 CMP R0, #0
.text:0004C208 BNE loc_4C34C
.text:0004C208
.text:0004C20C ADD R0, SP, #0x58+var_40
.text:0004C210 LDR R5, =aProxySharpv1_9
.text:0004C214 ADD R1, SP, #0x58+var_34
.text:0004C218 STR R0, [SP,#0x58+cbData]
.text:0004C21C STR R1, [SP,#0x58+lpData]
.text:0004C220 MOV R6, #0x10
.text:0004C224 LDR R0, [SP,#0x58+hKey] ; hKey
.text:0004C228 ADD R3, SP, #0x58+Type ; lpType
.text:0004C22C MOV R2, #0 ; lpReserved
.text:0004C230 STR R6, [SP,#0x58+var_40]
.text:0004C234 MOV R1, R5 ; lpValueName
.text:0004C238 BL RegQueryValueExW
.text:0004C238
.text:0004C23C CMP R0, #0
.text:0004C240 BNE loc_4C2CC
.text:0004C240
.text:0004C244 ADD R0, SP, #0x58+SystemTime ; lpSystemTime
.text:0004C248 BL GetLocalTime=========》取本地时间
.text:0004C248
.text:0004C24C LDRH R0, [SP,#0x58+SystemTime]
.text:0004C250 LDRH R3, [SP,#0x58+var_34]
.text:0004C254 MOV R0, R0,LSL#16
.text:0004C258 LDRH R5, [SP,#0x58+SystemTime.wMonth]===》取月
.text:0004C25C MOV R1, R0,LSR#16
.text:0004C260 LDRH R6, [SP,#0x58+var_34+2]
.text:0004C264 MOV R2, R3,LSL#16
.text:0004C268 MOV R0, #0x16C
.text:0004C26C SUB R2, R1, R2,LSR#16
.text:0004C270 ORR R0, R0, #1
.text:0004C274 MUL R4, R2, R0
.text:0004C278 MOV R0, R5,LSL#16
.text:0004C27C MOV R1, R0,LSR#16
.text:0004C280 MOV R3, R6,LSL#16
.text:0004C284 SUB R2, R1, R3,LSR#16
.text:0004C288 MOV R0, #0x1E
.text:0004C28C MLA R3, R2, R0, R4
.text:0004C290 LDRH R0, [SP,#0x58+var_2E]
.text:0004C294 MOV R1, R0,LSL#16
.text:0004C298 LDRH R0, [SP,#0x58+SystemTime.wDay]取天
.text:0004C29C SUB R2, R3, R1,LSR#16
.text:0004C2A0 MOV R1, R0,LSL#16
.text:0004C2A4 ADDS R3, R2, R1,LSR#16
.text:0004C2A8 BMI loc_4C338
.text:0004C2A8
.text:0004C2AC CMP R3, #0x17 ===》r3是已用天数和23比较看看是不是过期
.text:0004C2B0 BGE loc_4C338
.text:0004C2B0
.text:0004C2B4 LDR R0, [SP,#0x58+hKey] ; hKey
.text:0004C2B8 RSB R7, R3, #0x17
.text:0004C2BC BL RegCloseKey
.text:0004C2BC
.text:0004C2C0 MOV R0, R7
.text:0004C2C4 ADD SP, SP, #0x44
.text:0004C2C8 LDMFD SP!, {R4-R7,PC} ; lpData
.text:0004C2C8
.text:0004C2CC ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0004C2CC
.text:0004C2CC loc_4C2CC ; CODE XREF: sub_4C1D0+70j
.text:0004C2CC ADD R0, SP, #0x58+var_34 ; lpSystemTime
.text:0004C2D0 BL GetLocalTime
.text:0004C2D0
.text:0004C2D4 STR R7, [SP,#0x58+lpSecurityAttributes]
.text:0004C2D8 ADD R3, SP, #0x58+var_38
.text:0004C2DC STR R7, [SP,#0x58+cbData]
.text:0004C2E0 ADD R0, SP, #0x58+hKey
.text:0004C2E4 STR R3, [SP,#0x58+lpdwDisposition]
.text:0004C2E8 STR R0, [SP,#0x58+phkResult]
.text:0004C2EC MOV R3, #0 ; lpClass
.text:0004C2F0 MOV R2, #0 ; Reserved
.text:0004C2F4 STR R7, [SP,#0x58+lpData]
.text:0004C2F8 MOV R1, R4 ; lpSubKey
.text:0004C2FC MOV R0, #0x80000001 ; hKey
.text:0004C300 BL RegCreateKeyExW=====》建立一个新的注册表键值
.text:0004C300
.text:0004C304 CMP R0, #0
.text:0004C308 MOVNE R0, #0x17
.text:0004C30C ADDNE SP, SP, #0x44
.text:0004C310 LDMNEFD SP!, {R4-R7,PC}
.text:0004C314 STR R6, [SP,#0x58+cbData]
.text:0004C318 ADD R0, SP, #0x58+var_34
.text:0004C31C STR R0, [SP,#0x58+lpData]
.text:0004C320 MOV R3, #3 ; dwType
.text:0004C324 MOV R2, #0 ; Reserved
.text:0004C328 MOV R1, R5 ; lpValueName
.text:0004C32C LDR R0, [SP,#0x58+hKey] ; hKey
.text:0004C330 BL RegSetValueExW =====》写入注册表键值,这部分是处理第一次试用建立的日期时间
.text:0004C330
.text:0004C334 MOV R7, #0x17
.text:0004C338
.text:0004C338 loc_4C338 ; CODE XREF: sub_4C1D0+D8j
.text:0004C338 ; sub_4C1D0+E0j
.text:0004C338 LDR R0, [SP,#0x58+hKey] ; hKey
.text:0004C33C BL RegCloseKey
.text:0004C33C
.text:0004C340 MOV R0, R7
.text:0004C344 ADD SP, SP, #0x44
.text:0004C348 LDMFD SP!, {R4-R7,PC}
.text:0004C348
.text:0004C34C ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0004C34C
.text:0004C34C loc_4C34C ; CODE XREF: sub_4C1D0+38j
.text:0004C34C LDR R7, [SP,#0x58+var_38]
.text:0004C350 MOV R0, R7
.text:0004C354 ADD SP, SP, #0x44
.text:0004C358 LDMFD SP!, {R4-R7,P
========================================================
--------------------------------------------------------------------------------
【经验总结】
经过分析发现.text:0004BEB4是日期判断的关键改法有很多!比较好的一个改发就是
改0004C240 BNE loc_4C2CC========》BAL loc_4C2CC即可去处日期限制!
用winhex改完存盘测试ok!这个程序是我破解的第一个ppc程序总体感觉ppc的程序只要有毅力和耐心还是比较容易破解的!
如果用ida想调试ppc程序的话必须有有一台智能手机pda,没有手机听说可以用模拟器来调试!其实这个
程序还有可以再解的完美些!注意.text:0004BE8C(1)处的call经过分析发现这个call是注册码验证的call,我是赖的分
析了
有兴趣的朋友可以自己研究!再次感谢你耐心的看完这篇文章,希望对想研究PocketPC破解的初学者有所帮助!
--------------------------------------------------------------------------------
【版权声明】: 本文原创于大老主页, 转载请注明作者并保持文章的完整, 谢谢!
2006年07月09日 凌晨02:59:20
加密狗杀狗专业户!
http://dalao2002.yeah.net -
C语言教程第九章:预处理
2007-05-31 09:54:16
作者:佚名 文章来源:未知 点击数: 预处理
概述
在前面各章中,已多次使用过以“#”号开头的预处理命令。如包含命令# include,宏定义命令# define等。在源程序中这些命令都放在函数之外, 而且一般都放在源文件的前面,它们称为预处理部分。
所谓预处理是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作。预处理是C语言的一个重要功能, 它由预处理程序负责完成。当对一个源文件进行编译时, 系统将自动引用预处理程序对源程序中的预处理部分作处理, 处理完毕自动进入对源程序的编译。
C语言提供了多种预处理功能,如宏定义、文件包含、 条件编译等。合理地使用预处理功能编写的程序便于阅读、修改、 移植和调试,也有利于模块化程序设计。本章介绍常用的几种预处理功能。
宏定义
在C语言源程序中允许用一个标识符来表示一个字符串, 称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换, 这称为“宏代换”或“宏展开”。
宏定义是由源程序中的宏定义命令完成的。 宏代换是由预处理程序自动完成的。在C语言中,“宏”分为有参数和无参数两种。 下面分别讨论这两种“宏”的定义和调用。
无参宏定义
无参宏的宏名后不带参数。其定义的一般形式为: #define 标识符 字符串 其中的“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。 “标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。在前面介绍过的符号常量的定义就是一种无参宏定义。 此外,常对程序中反复使用的表达式进行宏定义。例如: # define M (y*y+3*y) 定义M表达式(y*y+3*y)。在编写源程序时,所有的(y*y+3*y)都可由M代替,而对源程序作编译时,将先由预处理程序进行宏代换,即用(y*y+3*y)表达式去置换所有的宏名M,然后再进行编译。
#define M (y*y+3*y)
main(){
int s,y;
printf("input a number: ");
scanf("%d",&y);
s=3*M+4*M+5*M;
printf("s=%d\n",s);
}
上例程序中首先进行宏定义,定义M表达式(y*y+3*y),在s= 3*M+4*M+5* M中作了宏调用。在预处理时经宏展开后该语句变为:s=3*(y*y+3*y)+4(y*y+3*y)+5(y*y+3*y);但要注意的是,在宏定义中表达式(y*y+3*y)两边的括号不能少。否则会发生错误。
当作以下定义后: #difine M y*y+3*y在宏展开时将得到下述语句: s=3*y*y+3*y+4*y*y+3*y+5*y*y+3*y;这相当于; 3y2+3y+4y2+3y+5y2+3y;显然与原题意要求不符。计算结果当然是错误的。 因此在作宏定义时必须十分注意。应保证在宏代换之后不发生错误。对于宏定义还要说明以下几点:
1. 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。
2. 宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。
3. 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结 束。如要终止其作用域可使用# undef命令,例如: # define PI 3.14159
main()
{
……
}
# undef PIPI的作用域
f1()
....表示PI只在main函数中有效,在f1中无效。
4. 宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换。
#define OK 100
main()
{
printf("OK");
printf("\n");
}
上例中定义宏名OK表示100,但在printf语句中OK被引号括起来,因此不作宏代换。程序的运行结果为:OK这表示把“OK”当字符串处理。
5. 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层代换。例如: #define PI 3.1415926
#define S PI*y*y /* PI是已定义的宏名*/对语句: printf("%f",s);在宏代换后变为: printf("%f",3.1415926*y*y);
6. 习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母。
7. 可用宏定义表示数据类型,使书写方便。例如: #define STU struct stu在程序中可用STU作变量说明: STU body[5],*p;#define INTEGER int 在程序中即可用INTEGER作整型变量说明: INTEGER a,b; 应注意用宏定义表示数据类型和用typedef定义数据说明符的区别。宏定义只是简单的字符串代换,是在预处理完成的,而typedef是在编译时处理的,它不是作简单的代换, 而是对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。请看下面的例子: #define PIN1 int* typedef (int*) PIN2;从形式上看这两者相似, 但在实际使用中却不相同。下面用PIN1,PIN2说明变量时就可以看出它们的区别: PIN1 a,b;在宏代换后变成 int *a,b;表示a是指向整型的指针变量,而b是整型变量。然而:PIN2 a,b;表示a,b都是指向整型的指针变量。因为PIN2是一个类型说明符。由这个例子可见,宏定义虽然也可表示数据类型, 但毕竟是作字符
代换。在使用时要分外小心,以避出错。
8. 对“输出格式”作宏定义,可以减少书写麻烦。例9.3 中就采用了这种方法。
#define P printf
#define D "%d\n"
#define F "%f\n"
main(){
int a=5, c=8, e=11;
float b=3.8, d=9.7, f=21.08;
P(D F,a,b);
P(D F,c,d);
P(D F,e,f);
}
C语言允许宏带有参数。在宏定义中的参数称为形式参数, 在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开, 而且要用实参去代换形参。
带参宏定义的一般形式为: #define 宏名(形参表) 字符串 在字符串中含有各个形参。带参宏调用的一般形式为: 宏名(实参表);
例如:
#define M(y) y*y+3*y /*宏定义*/
:
k=M(5); /*宏调用*/
: 在宏调用时,用实参5去代替形参y, 经预处理宏展开后的语句
为: k=5*5+3*5
#define MAX(a,b) (a>b)?a:b
main(){
int x,y,max;
printf("input two numbers: ");
scanf("%d%d",&x,&y);
max=MAX(x,y);
printf("max=%d\n",max);
}
上例程序的第一行进行带参宏定义,用宏名MAX表示条件表达式(a>b)?a:b,形参a,b均出现在条件表达式中。程序第七行max=MAX(x,
y)为宏调用,实参x,y,将代换形参a,b。宏展开后该语句为: max=(x>y)?x:y;用于计算x,y中的大数。对于带参的宏定义有以下问题需要说明:
1. 带参宏定义中,宏名和形参表之间不能有空格出现。
例如把: #define MAX(a,b) (a>b)?a:b写为: #define MAX (a,b) (a>b)?a:b 将被认为是无参宏定义,宏名MAX代表字符串 (a,b)(a>b)?a:b。
宏展开时,宏调用语句: max=MAX(x,y);将变为: max=(a,b)(a>b)?a:b(x,y);这显然是错误的。
2. 在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。而宏调用中的实参有具体的值。要用它们去代换形参,因此必须作类型说明。这是与函数中的情况不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”。而在带参宏中,只是符号代换,不存在值传递的问题。
3. 在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。
#define SQ(y) (y)*(y)
main(){
int a,sq;
printf("input a number: ");
scanf("%d",&a);
sq=SQ(a+1);
printf("sq=%d\n",sq);
}
上例中第一行为宏定义,形参为y。程序第七行宏调用中实参为a+1,是一个表达式,在宏展开时,用a+1代换y,再用(y)*(y) 代换SQ,得到如下语句: sq=(a+1)*(a+1); 这与函数的调用是不同的, 函数调用时要把实参表达式的值求出来再赋予形参。 而宏代换中对实参表达式不作计算直接地照原样代换。
4. 在宏定义中,字符串内的形参通常要用括号括起来以避免出错。 在上例中的宏定义中(y)*(y)表达式的y都用括号括起来,因此结果是正确的。如果去掉括号,把程序改为以下形式:
#define SQ(y) y*y
main(){
int a,sq;
printf("input a number: ");
scanf("%d",&a);
sq=SQ(a+1);
printf("sq=%d\n",sq);
}
运行结果为:input a number:3
sq=7 同样输入3,但结果却是不一样的。问题在哪里呢? 这是由于代换只作符号代换而不作其它处理而造成的。 宏代换后将得到以下语句: sq=a+1*a+1; 由于a为3故sq的值为7。这显然与题意相违,因此参数两边的括号是不能少的。即使在参数两边加括号还是不够的,请看下面程序:
#define SQ(y) (y)*(y)
main(){
int a,sq;
printf("input a number: ");
scanf("%d",&a);
sq=160/SQ(a+1);
printf("sq=%d\n",sq);
}
本程序与前例相比,只把宏调用语句改为: sq=160/SQ(a+1); 运行本程序如输入值仍为3时,希望结果为10。但实际运行的结果如下:input a number:3 sq=160为什么会得这样的结果呢?分析宏调用语句,在宏代换之后变为: sq=160/(a+1)*(a+1);a为3时,由于“/”和“*”运算符优先级和结合性相同, 则先作160/(3+1)得40,再作40*(3+1)最后得160。为了得到正确答案应在宏定义中的整个字符串外加括号, 程序修改如下
#define SQ(y) ((y)*(y))
main(){
int a,sq;
printf("input a number: ");
scanf("%d",&a);
sq=160/SQ(a+1);
printf("sq=%d\n",sq);
}
以上讨论说明,对于宏定义不仅应在参数两侧加括号, 也应在整个字符串外加括号。
5. 带参的宏和带参函数很相似,但有本质上的不同,除上面已谈到的各点外,把同一表达式用函数处理与用宏处理两者的结果有可能是不同的。main(){
int i=1;
while(i<=5)
printf("%d\n",SQ(i++));
}
SQ(int y)
{
return((y)*(y));
}#define SQ(y) ((y)*(y))
main(){
int i=1;
while(i<=5)
printf("%d\n",SQ(i++));
}
在上例中函数名为SQ,形参为Y,函数体表达式为((y)*(y))。在例9.6中宏名为SQ,形参也为y,字符串表达式为(y)*(y))。 两例是相同的。例9.6的函数调用为SQ(i++),例9.7的宏调用为SQ(i++),实参也是相同的。从输出结果来看,却大不相同。分析如下:在例9.6中,函数调用是把实参i值传给形参y后自增1。 然后输出函数值。因而要循环5次。输出1~5的平方值。而在例9.7中宏调用时,只作代换。SQ(i++)被代换为((i++)*(i++))。在第一次循环时,由于i等于1,其计算过程为:表达式中前一个i初值为1,然后i自增1变为2,因此表达式中第2个i初值为2,两相乘的结果也为2,然后i值再自增1,得3。在第二次循环时,i值已有初值为3,因此表达式中前一个i为3,后一个i为4, 乘积为12,然后i再自增1变为5。进入第三次循环,由于i 值已为5,所以这将是最后一次循环。计算表达式的值为5*6等于30。i值再自增1变为6,不再满足循环条件,停止循环。从以上分析可以看出函数调用和宏调用二者在形式上相似, 在本质上是完全不同的。
6. 宏定义也可用来定义多个语句,在宏调用时,把这些语句又代换到源程序内。看下面的例子。
#define SSSV(s1,s2,s3,v) s1=l*w;s2=l*h;s3=w*h;v=w*l*h;
main(){
int l=3,w=4,h=5,sa,sb,sc,vv;
SSSV(sa,sb,sc,vv);
printf("sa=%d\nsb=%d\nsc=%d\nvv=%d\n",sa,sb,sc,vv);
}
程序第一行为宏定义,用宏名SSSV表示4个赋值语句,4 个形参分别为4个赋值符左部的变量。在宏调用时,把4 个语句展开并用实参代替形参。使计算结果送入实参之中。
作者:佚名 文章来源:未知 点击数:
文件包含
文件包含是C预处理程序的另一个重要功能。文件包含命令行的一般形式为: #include"文件名" 在前面我们已多次用此命令包含过库函数的头文件。例如:
#include"stdio.h"
#include"math.h"
文件包含命令的功能是把指定的文件插入该命令行位置取代该命令行, 从而把指定的文件和当前的源程序文件连成一个源文件。在程序设计中,文件包含是很有用的。 一个大的程序可以分为多个模块,由多个程序员分别编程。 有些公用的符号常量或宏定义等可单独组成一个文件, 在其它文件的开头用包含命令包含该文件即可使用。这样,可避免在每个文件开头都去书写那些公用量, 从而节省时间,并减少出错。
对文件包含命令还要说明以下几点:
1. 包含命令中的文件名可以用双引号括起来,也可以用尖括号括起来。例如以下写法都是允许的: #include"stdio.h" #include<math.h> 但是这两种形式是有区别的:使用尖括号表示在包含文件目录中去查找(包含目录是由用户在设置环境时设置的), 而不在源文件目录去查找; 使用双引号则表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查找。 用户编程时可根据自己文件所在的目录来选择某一种命令形式。
2. 一个include命令只能指定一个被包含文件, 若有多个文件要包含,则需用多个include命令。3. 文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。
条件编译
预处理程序提供了条件编译的功能。 可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件。 这对于程序的移植和调试是很有用的。 条件编译有三种形式,下面分别介绍:
1. 第一种形式:
#ifdef 标识符
程序段1
#else
程序段2
#endif
它的功能是,如果标识符已被 #define命令定义过则对程序段1进行编译;否则对程序段2进行编译。如果没有程序段2(它为空),本格式中的#else可以没有, 即可以写为:
#ifdef 标识符
程序段 #endif
#define NUM ok
main(){
struct stu
{
int num;
char *name;
char sex;
float score;
} *ps;
ps=(struct stu*)malloc(sizeof(struct stu));
ps->num=102;
ps->name="Zhang ping";
ps->sex='M';
ps->score=62.5;
#ifdef NUM
printf("Number=%d\nScore=%f\n",ps->num,ps->score);
#else
printf("Name=%s\nSex=%c\n",ps->name,ps->sex);
#endif
free(ps);
}
由于在程序的第16行插入了条件编译预处理命令, 因此要根据NUM是否被定义过来决定编译那一个printf语句。而在程序的第一行已对NUM作过宏定义,因此应对第一个printf语句作编译故运行结果是输出了学号和成绩。在程序的第一行宏定义中,定义NUM表示字符串OK,其实也可以为任何字符串,甚至不给出任何字符串,写为: #define NUM 也具有同样的意义。 只有取消程序的第一行才会去编译第二个printf语句。读者可上机试作。
2. 第二种形式:
#ifndef 标识符
程序段1
#else
程序段2
#endif
与第一种形式的区别是将“ifdef”改为“ifndef”。它的功能是,如果标识符未被#define命令定义过则对程序段1进行编译, 否则对程序段2进行编译。这与第一种形式的功能正相反。
3. 第三种形式:
#if 常量表达式
程序段1
#else
程序段2
#endif
它的功能是,如常量表达式的值为真(非0),则对程序段1 进行编译,否则对程序段2进行编译。因此可以使程序在不同条件下,完成不同的功能
#define R 1
main(){
float c,r,s;
printf ("input a number: ");
scanf("%f",&c);
#if R
r=3.14159*c*c;
printf("area of round is: %f\n",r);
#else
s=c*c;
printf("area of square is: %f\n",s);
#endif
}
本例中采用了第三种形式的条件编译。在程序第一行宏定义中,定义R为1,因此在条件编译时,常量表达式的值为真, 故计算并输出圆面积。上面介绍的条件编译当然也可以用条件语句来实现。 但是用条件语句将会对整个源程序进行编译,生成的目标代码程序很长,而采用条件编译,则根据条件只编译其中的程序段1或程序段2, 生成的目标程序较短。如果条件选择的程序段很长, 采用条件编译的方法是十分必要的。
本章小结
1. 预处理功能是C语言特有的功能,它是在对源程序正式编译前由预处理程序完成的。程序员在程序中用预处理命令来调用这些功能。
2. 宏定义是用一个标识符来表示一个字符串,这个字符串可以是常量、变量或表达式。在宏调用中将用该字符串代换宏名。
3. 宏定义可以带有参数,宏调用时是以实参代换形参。而不是“值传送”。
4. 为了避免宏代换时发生错误,宏定义中的字符串应加括号,字符串中出现的形式参数两边也应加括号。
5. 文件包含是预处理的一个重要功能,它可用来把多个源文件连接成一个源文件进行编译,结果将生成一个目标文件。
6. 条件编译允许只编译源程序中满足条件的程序段,使生成的目标程序较短,从而减少了内存的开销并提高了程序的效率。
7. 使用预处理功能便于程序的修改、阅读、移植和调试,也便于实现模块化程序设计。 -
C语言基础教程(一)基础篇
2007-05-31 09:54:16
作者:王大刚 1.1 C 语言的产生与发展
C 语言是1972年由美国的Dennis Ritchie设计发明的, 并首次在UNIX操作系统
的 DEC PDP-11 计算机上使用。 它由早期的编程语言 BCPL( Basic Combind
Programming Language) 发展演变而来。在1970年, AT&T 贝尔实验室的 Ken
Thompson根据BCPL语言设计出较先进的并取名为 B的语言, 最后导了C 语言的问世。
随着微型计算机的日益普及, 出现了许多C 语言版本。由于没有统一的标准,
使得这些C 语言之间出现了一些不一致的地方。为了改变这种情况, 美国国家标准
研究所(ANSI)为C 语言制定了一套ANSI标准, 成为现行的C语言标准。1.2 C 语言的特点
C 语言发展如此迅速, 而且成为最受欢迎的语言之一, 主要因为它具有强大的
功能。许多著名的系统软件, 如DBASE Ⅲ PLUS、DBASE Ⅳ 都是由C 语言编写的。
用C 语言加上一些汇编语言子程序, 就更能显示C 语言的优势了, 象PC- DOS 、
WORDSTAR等就是用这种方法编写的。归纳起来C 语言具有下列特点:
1. C是中级语言
它把高级语言的基本结构和语句与低级语言的实用性结合起来。C 语言可以象
汇编语言一样对位、字节和地址进行操作, 而这三者是计算机最基本的工作单元。
2. C是结构式语言
结构式语言的显著特点是代码及数据的分隔化, 即程序的各个部分除了必要的
信息交流外彼此独立。这种结构化方式可使程序层次清晰, 便于使用、维护以及调
试。C 语言是以函数形式提供给用户的, 这些函数可方便的调用, 并具有多种循
环、条件语句控制程序流向, 从而使程序完全结构化。
3. C语言功能齐全
C 语言具有各种各样的数据类型, 并引入了指针概念, 可使程序效率更高。另
外C 语言也具有强大的图形功能, 支持多种显示器和驱动器。而且计算功能、逻辑
判断功能也比较强大, 可以实现决策目的。
4. C语言适用范围大
C 语言还有一个突出的优点就是适合于多种操作系统, 如DOS、UNIX,也适用于
多种机型。作者:王大刚 1.3 Turbo C 概述
1.3.1 Turbo C 的产生与发展
Turbo C 是美国Borland 公司的产品,Borland公司是一家专门从事软件开发、
研制的大公司。该公司相继推出了一套 Turbo系列软件, 如Turbo BASIC, Turbo
Pascal, Turbo Prolog, 这些软件很受用户欢迎。该公司在1987年首次推出Turbo
C 1.0 产品, 其中使用了全然一新的集成开发环境, 即使用了一系列下拉式菜单,
将文本编辑、程序编译、连接以及程序运行一体化, 大大方便了程序的开发。1988
年, Borland 公司又推出Turbo C1.5版本, 增加了图形库和文本窗口函数库等, 而
Turbo C 2.0 则是该公司1989年出版的。Turbo C2.0在原来集成开发环境的基础上
增加了查错功能, 并可以在Tiny模式下直接生成.COM (数据、代码、堆栈处在同一
64K 内存中) 文件。还可对数学协处理器 (支持8087/80287/80387等)进行仿真。
Borland 公司后来又推出了面向对象的程序软件包Turbo C++, 它继承发展
Turbo C 2.0 的集成开发环境, 并包含了面向对象的基本思想和设计方法。
1991年为了适用Microsoft 公司的Windows 3.0 版本, Borland 公司又将Turbo
C++ 作了更新, 即Turbo C 的新一代产品Borlandc C++也已经问世了。
1.3.2 Turbo C 2.0基本配置要求
Turbo C 2.0可运行于IBM-PC系列微机, 包括XT, AT及IBM 兼容机。 此时要求
DOS 2.0或更高版本支持, 并至少需要448K的RAM, 可在任何彩、单色80列监视器上
运行。支持数学协处理器芯片, 也可进行浮点仿真, 这将加快程序的执行。
1.3.3 Turbo C 2.0内容简介
Turbo C 2.0有六张低密软盘(或两张高密软盘)。下面对Turbo C 2.0的主要文
件作一简单介绍:
INSTALL.EXE 安装程序文件
TC.EXE 集成编译
TCINST.EXE 集成开发环境的配置设置程序
TCHELP.TCH 帮助文件
THELP.COM 读取TCHELP.TCH的驻留程序
README 关于Turbo C的信息文件
TCCONFIG.EXE 配置文件转换程序
MAKE.EXE 项目管理工具
TCC.EXE 命令行编译
TLINK.EXE Turbo C系列连接器
TLIB.EXE Turbo C系列库管理工具
C0?.OBJ 不同模式启动代码
C?.LIB 不同模式运行库
GRAPHICS.LIB 图形库
EMU.LIB 8087仿真库
FP87.LIB 8087库
*.H Turbo C头文件
*.BGI 不同显示器图形驱动程序
*.C Turbo C例行程序(源文件)
其中: 上面的?分别为:
T Tiny(微型模式)
S Small(小模式)
C Compact(紧凑模式)
M Medium(中型模式)
L Large(大模式)
H Huge(巨大模式)
作者:王大刚 文章来源:不详 点击数: 1.4 Turbo C 2.0的安装和启动
Turbo C 2.0的安装非常简单, 只要将1#盘插入A驱动器中, 在DOS的"A>" 下键
入:
A>INSTALL
即可, 此时屏幕上显示三种选择:
1. 在硬盘上创造一个新目录来安装整个Turbo C 2.0系统。
2. 对Turbo C 1.5更新版本。
这样的安装将保留原来对选择项、颜色和编辑功能键的设置。
3. 为只有两个软盘而无硬盘的系统安装Turbo C 2.0。
这里假定按第一种选择进行安装, 只要在安装过程中按对盘号的提示, 顺序插
入各个软盘, 就可以顺利地进行安装, 安装完毕将在C盘根目录下建立一个TC 子目
录, TC下还建立了两个了目录LIB和INCLUDE, LIB子目录中存放库文件, INCLUDE
子目录中存放所有头文件。
运行Turbo C 2.0时, 只要在TC 子目录下键入TC并回车即可进入Turbo C 2. 0
集成开发环境。1.5 Turbo C 2.0集成开发环境的使用
进入Turbo C 2.0集成开发环境中后, 屏幕上显示:
──────────────────────────────
File Edit Run Compile Project Options Debug Break/watch
┌────────────Edit──────────────┐
│ Line 1 Col 1 Insert Indent Tab File Unindent c:NONAME.C│
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│─────────Message─────────────── │
│ │
│ │
└────────────────────────────┘
F1-Help F5-Zoom F6-Switch F7-Trace F8-Step F9-Make F10-Menu
───────────────────────────────
其中顶上一行为Turbo C 2.0 主菜单, 中间窗口为编辑区, 接下来是信息窗
口, 最底下一行为参考行。这四个窗口构成了Turbo C 2.0的主屏幕, 以后的编程、
编译、调试以及运行都将在这个主屏幕中进行。下面详细介绍主菜单的内容。
1. Turbo C 2.0的双界符包括以下几种符号:不详 点击数: 1.5.1 主菜单
主菜单 在Turbo C 2.0主屏幕顶上一行, 显示下列内容:
File Edit Run Compile Project Options Debug Break/watch
除Edit外, 其它各项均有子菜单, 只要用Alt加上某项中第一个字母(即大写字
母), 就可进入该项的子菜单中。
一、File(文件)菜单
按Alt+F可进入File菜单, 该菜单包括以下内容:
.Load(加载)
装入一个文件, 可用类似DOS的通配符(如*.C)来进行列表选择。也可装入其它
扩展名的文件, 只要给出文件名(或只给路径)即可。该项的热键为F3, 即只要在主
菜单中按F3即可进入该项, 而不需要先进入File菜单再选此项。
.Pick(选择)
将最近装入编辑窗口的8个文件列成一个表让用户选择, 选择后将该程序装入
编辑区, 并将光标置在上次修改过的地方。其热健为Alt-F3。
.New(新文件)
说明文件是新的, 缺省文件名为NONAME.C, 存盘时可改名。
.Save(存盘)
将编辑区中的文件存盘, 若文件名是NONAME.C时, 将询问是否更改文件名, 其
热键为F2。
.Write to(存盘)
可由用户给出文件名将编辑区中的文件存盘, 若该文件已存在, 则询问要不要
覆盖。
.Directory(目录)
显示目录及目录中的文件, 并可由用户选择。
.Change dir(改变目录)
显示当前目录, 用户可以改变显示的目录。
.Os shell(暂时退出)
暂时退出Turbo C 2.0到DOS提示符下, 此时可以运行DOS 命令, 若想回到
Turbo C 2.0中, 只要在DOS状态下键入EXIT即可。
.Quit(退出)
退出Turbo C 2.0, 返回到DOS操作系统中, 其热键为Alt+X。
说明:
以上各项可用光标键移动色棒进行选择, 回车则执行。也可用每一项的第一个
大写字母直接选择。若要退到主菜单或从它的下一级菜单列表框退回均可用Esc键,
Turbo C 2.0所有菜单均采用这种方法进行操作, 以下不再说明。
二、Edit(编辑)菜单
按Alt+E可进入编辑菜单, 若再回车, 则光标出现在编辑窗口, 此时用户可以
进行文本编辑。
编辑方法基本与wordstar相同, 可用F1键获得有关编辑方法的帮助信息。
与编辑有关的功能键如下:
F1 获得Turbo C 2.0编辑命令的帮助信息
F5 扩大编辑窗口到整个屏幕
F6 在编辑窗口与信息窗口之间进行切换
F10 从编辑窗口转到主菜单
编辑命令简介:
PageUp 向前翻页
PageDn 向后翻页
Home 将光标移到所在行的开始
End 将光标移到所在行的结尾
Ctrl+Y 删除光标所在的一行
Ctrl+T 删除光标所在处的一个词
Ctrl+KB 设置块开始
Ctrl+KK 设置块结尾
Ctrl+KV 块移动
Ctrl+KC 块拷贝
Ctrl+KY 块删除
Ctrl+KR 读文件
Ctrl+KW 存文件
Ctrl+KP 块文件打印
Ctrl+F1 如果光标所在处为Turbo C 2.0库函数, 则获得有关该函数的帮助
信息
Ctrl+Q[ 查找Turbo C 2.0双界符的后匹配符
Ctrl+Q] 查找Turbo C 2.0双界符的前匹配符
花括符 {和}
尖括符 <和>
圆括符 (和)
方括符 [和]
注释符 /*和*/
双引号 "
单引号 '
2. Turbo C 2.0在编辑文件时还有一种功能, 就是能够自动缩进, 即光标定位
和上一个非空字符对齐。在编辑窗口中, Ctrl+OL为自动缩进开关的控制键。
三、Run(运行)菜单
按Alt+R可进入Run菜单, 该菜单有以下各项:
.Run(运行程序)
运行由Project/Project name项指定的文件名或当前编辑区的文件。如果对上
次编译后的源代码未做过修改, 则直接运行到下一个断点(没有断点则运行到结束)。
否则先进行编译、连接后才运行, 其热键为Ctrl+F9。
.Program reset(程序重启)
中止当前的调试, 释放分给程序的空间, 其热键为Ctrl+F2。
.Go to cursor(运行到光标处)
调试程序时使用, 选择该项可使程序运行到光标所在行。光标所在行必须为一
条可执行语句, 否则提示错误。其热键为F4。
.Trace into(跟踪进入)
在执行一条调用其它用户定义的子函数时, 若用Trace into项, 则执行长条将
跟踪到该子函数内部去执行, 其热键为F7。
.Step over(单步执行)
执行当前函数的下一条语句, 即使用户函数调用, 执行长条也不会跟踪进函数
内部, 其热键为F8。
.User screen(用户屏幕)
显示程序运行时在屏幕上显示的结果。其热键为Alt+F5。
四、Compile(编译)菜单
按Alt+C可进入Compile菜单, 该菜单有以下几个内容:
.Compile to OBJ(编译生成目标码)
将一个C源文件编译生成.OBJ目标文件, 同时显示生成的文件名。其热键为
Alt+F9。
.Make EXE file(生成执行文件)
此命令生成一个.EXE的文件, 并显示生成的.EXE文件名。其中.EXE文件名是下
面几项之一。
1. 由Project/Project name说明的项目文件名。
2. 若没有项目文件名, 则由Primary C file说明的源文件。
3. 若以上两项都没有文件名, 则为当前窗口的文件名。
.Link EXE file(连接生成执行文件)
把当前.OBJ文件及库文件连接在一起生成.EXE文件。
.Build all(建立所有文件)
重新编译项目里的所有文件, 并进行装配生成.EXE文件。该命令不作过时检查
(上面的几条命令要作过时检查, 即如果目前项目里源文件的日期和时间与目标文
件相同或更早, 则拒绝对源文件进行编译)。
.Primary C file(主C文件)
当在该项中指定了主文件后, 在以后的编译中, 如没有项目文件名则编译此项
中规定的主C文件, 如果编译中有错误, 则将此文件调入编辑窗口, 不管目前窗口
中是不是主C文件。
.Get info(获得有关当前路径、源文件名、源文件字节大小、编译中的错误数
目、可用空间等信息。作者:王大刚 文章来源:不详 点击数: 五、Project(项目)菜单
按Alt+P可进入Project菜单, 该菜单包括以下内容:
.Project name(项目名)
项目名具有.PRJ的扩展名, 其中包括将要编译、连接的文件名。例如有一个程
序由file1.c, file2.c, file3.c组成, 要将这3个文件编译装配成一个file.exe的
执行文件, 可以先建立一个file.prj的项目文件, 其内容如下:
file1.c
file2.c
file3.c
此时将file.prj放入Project name项中, 以后进行编译时将自动对项目文件中
规定的三个源文件分别进行编译。然后连接成file.exe文件。
如果其中有些文件已经编译成.OBJ文件, 而又没有修改过, 可直接写上.OBJ扩
展名。此时将不再编译而只进行连接。
例如: file1.obj
file2.c
file3.c
将不对file1.c进行编译, 而直接连接。
说明:当项目文件中的每个文件无扩展名时, 均按源文件对待, 另外, 其中的文件也
可以是库文件, 但必须写上扩展名.LIB。
.Break make on(中止编译)
由用户选择是否在有Warining(警告)、Errors(错误)、Fatal Errors( 致命错
误)时或Link(连接)之前退出Make编译。
.Auto dependencies(自动依赖)
当开关置为on, 编译时将检查源文件与对应的.OBJ文件日期和时间, 否则不进
行检查。
.Clear project(清除项目文件)
清除Project/Project name中的项目文件名。
.Remove messages(删除信息)
把错误信息从信息窗口中清除掉。作者:王大刚 文章来源:不详 点击数: 六、Options(选择菜单)
按Alt+O可进入Options菜单, 该菜单对初学者来说要谨慎使用。
.Compiler(编译器)
本项选择又有许多子菜单, 可以让用户选择硬件配置、存储模型、调试技术、
代码优化、对话信息控制和宏定义。这些子菜单如下:
Model
共有Tiny, small, medium, compact, large, huge 六种不同模式可由同户选
择。
Define
打开一个宏定义框, 同户可输入宏定义。多重定义可同分号, 赋值可用等号。
Code generation
它又有许多任选项, 这些任选项告诉编译器产生什么样的目标代码。
Calling convention 可选择C或Pascal方式传递参数。
Instruction set 可选择8088/8086或80186/80286指令系列。
Floating point 可选择仿真浮点、数学协处理器浮点或无浮点运算。
Default char type 规定char的类型。
Alignonent 规定地址对准原则。
Merge duplicate strings 作优化用, 将重复的字符串合并在一起。
Standard stack frame. 产生一个标准的栈结构。
Test stack overflow 产生一段程序运行时检测堆栈溢出的代码。
Line number 在.OBJ文件中放进行号以供调试时用。
OBJ debug information 在.OBJ文件中产生调试信息。
Optimization
Optimize for 选择是对程序小型化还是对程序速度进行优
化处理。
Use register variable 用来选择是否允许使用寄存器变量。
Register optimization 尽可能使用寄存器变量以减少过多的取数操
作。
Jump optimization 通过去除多余的跳转和调整循环与开关语句
的办法, 压缩代码。
Source
Indentifier length 说明标识符有效字符的个数, 默认为32个。
Nested comments 是否允许嵌套注释。
ANSI keywords only 是只允许ANSI关键字还是也允许Turbo C
2.0关键字
Error
Error stop after 多少个错误时停止编译, 默认为25个。
Warning stop after 多少个警告错误时停止编译, 默认为100个。
Display warning
Portability warning 移植性警告错误。
ANSI Violations 侵犯了ANSI关键字的警告错误。
Common error 常见的警告错误。
Less common error 少见的警告错误。
Names 用于改变段(segment)、 组( group) 和类
(class)的名字, 默认值为CODE,DATA,BSS。.Linker(连接器)
本菜单设置有关连接的选择项, 它有以下内容:
Map file menu 选择是否产生.MAP文件。
Initialize segments 是否在连接时初始化没有初始化的段。
Devault libraries 是否在连接其它编译程序产生的目标文件时去寻
找其缺省库。
Graphics library 是否连接graphics库中的函数。
Warn duplicate symbols 当有重复符号时产生警告信息。
Stack warinig 是否让连接程序产生No stack的警告信息。
Case-sensitive link 是否区分大、小写字。
.Environment(环境)
本菜单规定是否对某些文件自动存盘及制表键和屏幕大小的设置
Message tracking
Current file 跟踪在编辑窗口中的文件错误。
All files 跟踪所有文件错误。
Off 不跟踪。
Keep message 编译前是否清除Message窗口中的信息。
Config auto save 选on时, 在Run, Shell或退出集成开发环境之前,
如果Turbo C 2.0的配置被改过, 则所做的改动
将存入配置文件中。选off时不存。
Edit auto save 是否在Run或Shell之前, 自动存储编辑的源文件。
Backup file 是否在源文件存盘时产生后备文件(.BAK文件)。
Tab size 设置制表键大小, 默认为8。
Zoomed windows 将现行活动窗口放大到整个屏幕, 其热键为F5。
Screen size 设置屏幕文本大小。
.Directories(路径)
规定编译、连接所需文件的路径, 有下列各项:
Include directories 包含文件的路径, 多个子目录用";"分开。
Library directories 库文件路径, 多个子目录用";"分开。
Output directoried 输出文件(.OBJ, .EXE, .MAP文件)的目录。
Turbo C directoried Turbo C 所在的目录。
Pick file name 定义加载的pick文件名, 如不定义则从current
pick file中取。
.Arguments(命令行参数)
允许用户使用命令行参数。
.Save options(存储配置)
保存所有选择的编译、连接、调试和项目到配置文件中, 缺省的配置文件为
TCCONFIG.TC。
.Retrive options
装入一个配置文件到TC中, TC将使用该文件的选择项作者:王大刚 文章来源:不详 点击数: 七、Debug(调试)菜单
按Alt+D可选择Debug菜单, 该菜单主要用于查错, 它包括以下内容:
Evaluate
Expression 要计算结果的表达式。
Result 显示表达式的计算结果。
New value 赋给新值。
Call stack 该项不可接触。而在Turbo C debuger 时用于检
查堆栈情况。
Find function 在运行Turbo C debugger时用于显示规定的函数。
Refresh display 如果编辑窗口偶然被用户窗口重写了可用此恢复
编辑窗口的内容。八、Break/watch(断点及监视表达式)
按Alt+B可进入Break/watch菜单, 该菜单有以下内容:
Add watch 向监视窗口插入一监视表达式。
Delete watch 从监视窗口中删除当前的监视表达式。
Edit watch 在监视窗口中编辑一个监视表达式。
Remove all watches 从监视窗口中删除所有的监视表达式。
Toggle breakpoint 对光标所在的行设置或清除断点。
Clear all breakpoints 清除所有断点。
View next breakpoint 将光标移动到下一个断点处。
作者:王大刚 文章来源:不详 点击数: 1.5.2 Turbo C 2.0的配置文件
所谓配置文件是包含Turbo C 2.0有关信息的文件, 其中存有编译、连接的选
择和路径等信息。
可以用下述方法建立Turbo C 2.0的配置:
1. 建立用户自命名的配置文件
可以从Options菜单中选择Options/Save options命令, 将当前集成开发环境
的所有配置存入一个由用户命名的配置文件中。下次启动TC时只要在DOS下键入:
tc/c<用户命名的配置文件名>
就会按这个配置文件中的内容作为Turbo C 2.0的选择。
2. 若设置Options/Environment/Config auto save 为on, 则退出集成开发环
境时, 当前的设置会自动存放到Turbo C 2.0配置文件TCCONFIG.TC中。Turbo C 在
启动时会自动寻找这个配置文件。
3. 用TCINST设置Turbo C的有关配置, 并将结果存入TC.EXE中。Turbo C 在启
动时, 若没有找到配置文件, 则取TC.EXE中的缺省值。

