`
mnfp20mnfp
  • 浏览: 17689 次
社区版块
存档分类
最新评论

如何破解Pocket PC (for ARM)软件

 
阅读更多

如何破解Pocket PC (for ARM)软件
2010年04月17日
  比较PC下的软件,Pocket PC上软件的破解是比较简单的。如果你有windows下软件的破解经历,那只要熟悉ARM汇编就够了。
  一. 所需知识
  1.熟悉C语言和ARM汇编语言。
  2.有Windows API编程的经验。
  二. 工具
  1. Embedded VC++或者VS.NET 2005,用于动态调试待破解程序;
  2. IDA Pro,最新版4.9,需要全版,这样能反汇编不同类型CPU的程序,用于静态分析;
  3. ResHacker,用于查看资源,找出敏感的字符串;
  4. 二进制编辑器,如UltraEdit,WinHex等,用于修改程序;
  5. 一种ARM的编译器,如EmbestIDE for ARM、ADS,SDT等,可以用于写一小段汇编代码,再嵌入到目标程序中,也可以用来熟悉ARM指令;
  6. 最好有一个pocket pc的设备(ARM CPU),有了vs.net 2005没有设备也可以:)
  三. 注册码验证方式与破解方式
  当我们输入一个软件的注册码时,软件必须与正确的注册码相比较,才能判断输入的正确与否,下面是常用的注册码验证方法。
  1.将owner name或email运算得到正确的注册码,再和输入的注册码比较;
  RealKeyCode = f(owner name/email);
  If( inputKeyCode == RealkeyCode)
  “注册成功”
  else
  “注册失败”
  要强制破解,可以跳过inputKeyCode == RealkeyCode判断,直接执行“注册成功”。如果要做注册机,则要读懂RealKeyCode = f(owner name/email)这段代码。
  如何快速找到注册码判断的入口点呢,这就要借助上面提及的工具了,很明显的标志是字符串“注册成功”与“注册失败”,当然在实际中提示是不完全相同的。如果提示信息以资源的形式保存,则要使用ResHacker查看;否则就需要反汇编程序。
  用IDA Pro反汇编时,在反汇编过程中有一个System DLL Directory要输入路径,最好将pocket pc \windows目录下的dll复制到一个文件夹(不是所有的都能复制),如C:\WINDOWS\CE。这些动态库可以是x86模拟器的,因为IDA只是关心他们的引出函数。
  找到提示信息后,一般很快能找出注册码比较点。
  拿ProWord为例,在ResHacker中查看字符串资源,并没有发现相关注册成功失败的信息,在对话框资源142中可以看出需要输入User name和unlock code。用Ida反汇编,在String窗口中可以发现:
  .data:00020CF4 00000044 unicode Thank you for registering ProWord
  .data:00020D38 00000030 unicode Not a valid Unlock code
  顺着串往上找,发现:
  .text:000178A0 BL sub_197C4 ;返回R0 == 0则注册码错误
  .text:000178A4 MOVS R3, R0
  .text:000178A8 BEQ loc_178D8
  .text:000178AC CMP R4, #0
  .text:000178B0 MOV R0, #0
  .text:000178B4 LDRNE R0, [R4,#0x20]
  .text:000178B8 BL sub_191D8
  .text:000178BC MOV R3, #1
  .text:000178C0 MOV R0, R4
  .text:000178C4 STR R3, [R4,#0x7C]
  .text:000178C8 BL mfcce300_1969
  .text:000178CC LDR R0, =aThankYouForReg
  .text:000178D0 B loc_178E8
  .text:000178D4 off_178D4 DCD aThankYouForReg ; DATA XREF: sub_17858+74 r
  .text:000178D4 ; "Thank you for registering ProWord"
  .text:000178D8 loc_178D8 ; CODE XREF: sub_17858+50 j
  .text:000178D8 LDR R0, =aNotAValidUnloc
  .text:000178DC B loc_178E8
  .text:000178E0 off_178E0 DCD aNotAValidUnloc ; DATA XREF: sub_17858+80 r
  .text:000178E0 ; "Not a valid Unlock code"
  sub_197C4是重点,进入看看,发现调用sub_19540,返回R0==0则注册码错,而且sub_19540有两个地方调用,一个是启动程序时验证注册码,一个是输入注册码时验证,因此要进入sub_19540修改返回值,如果在sub_19540外修改,则需要修改两次,如有遗漏,有时输入注册码虽然提示正确,但重新启动程序时会再次提醒非注册版本,这种错误经常出现!
  有的程序提示信息以串资源的形式保存,如:
  STRINGTABLE
  LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
  {
  2202, "Enter Code"
  2203, "Thank you for registering. \nNow you need to restart game to apply changes."
  }
  应用程序要显示字符串,首先要载入该串资源,用API则调用如下功能:
  int LoadString(HINSTANCE hInstance, UINT uID,
  LPTSTR lpBuffer, int cchBufferMax);
  在ARM中函数调用参数传递约定:
  func(R0,R1,R2,R3,SP,SP+4,…,SP+4*n),返回值在R0中。
  上例中uID = 2203 = 0x89D,在反汇编代码中应该有如下类似代码:
  MOV R1, #0x890 ;;
  -------------------------
  不是MOV R1, #0x89D的原因
  arm在32bit模式下,一条指令长度为4字节
  mov指令的操作数2(op2)占12位
  一种情况是:
  11--------8--7------------------0bit
  -------------------------------------
  |#循环移位|-----8位立即数-----|
  -------------------------------------
  当操作数大于255时,就需要通过移位操作来构成
  -------------------------
  ORR R1, R1, #0xD
  如何快速找到上述代码呢?可以在IDA中先生成.asm文件,File->Produce->Create ASM File。用Emeditor或其他可以用正则表示式查找功能的编辑器打开,查找MOV.*R.*#0x890,很快就能够发现。如果不太明白正则表示式,直接搜索#0x890也可,就是找到结果太多!
  如果串资源是53569,”xxxxxxxx” 53679 = 0xD597,一时不明白MOV R1, #0x???,
  就可以查找MOV.*R.*#0xD\d\d\d,找到后再缩小范围。
  2. 将owner name或email和输入的注册码分别运算得到中间值,比较二者
  imdKeyCode = f(owner name/email);
  imdKey1Code = g(inputKeyCode);
  if(imdKeyCode == imdKey1Code)
  “注册成功”
  else
  “注册失败”
  这种方法,不像方式1,并不将真正的注册码计算出来。
  3. 有些程序只需要输入注册码,如isilo,此时的验证方式是看输入的注册码是否满足某些条件,例如运算后某些位是否为指定的值。
  在实际程序中,验证注册码不一定只是比较一次,很多程序并不是立即判断输入注册码的正确与否,所以要具体对待。
  以上是注册码验证的比较常见的方式。
  四. 用EVC动态调试程序
  在静态分析出现困难时,可以使用EVC动态调试待破解程序。
  EVC菜单 File -> Open Workspace -> 文件类型选.exe ->打开,然后再Project ->Setting中设置download路径,将计算机与你的pocket pc连上,在EVC中选择POCKET PC 2002/2003 DEVICE,设置断点,Build -> Start Debug -> Go,然后操作你的Pocket pc,满足断点条件时,程序终止,这是可以调试程序了。
  用vs.net2005调试ce软件
  目前的方法不算是很好,暂时没有更好的,谁知道更好的方法,还请不要吝惜。
  1,运行vs.net 2005, 菜单“工具”->“连接到设备”,选择合适的平台;
  2,运行需要调试的目标程序;
  3,菜单“工具”->“附加到进程”,传输(P):选择“智能设备”,限定符(Q):选择合适的平台;
  附加到选择“本机(智能设备)代码”;
  在可用进程中选择代调试的进程;
  这时就可以调试该程序了。
  用这种方法可以直接看到注册码验证方式1中的注册码。
  如:
  .text:0009D434 ADD R1, R6, #0x84
  .text:0009D438 ADD R0, SP, #0x90
  .text:0009D43C BL wcscmp ; 注册码比较
  那么在内存单元中查看R0,R1所显示的内容,就可以知道正确的注册码了。
  如何破解Pocket PC (for ARM)软件【5】
  五 实例
  1.TrueFax (Windows Mobile 2003 Phone Edition v2.05 (PXA-CPU))
  http://www.ksesoftware.com/showarticle.php...9&sub=downloads
  用ResHacker 依次打开TF20PoomDll.dll,Truefax.exe,TruefaxLangComp20.dll
  在TruefaxLangComp20.dll中发现:
  STRINGTABLE
  LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
  {
  300, "The entered name is too short."
  301, "The reg.-no. does not fit with the user-name."
  302, "This version was registered successfully. Thank you for your interest in %s."
  303, "This trial version has expired!\nPlease register KSE Truefax."
  }
  反汇编Truefax.exe生成.asm文件,用正则表达式查找MOV.*R.*#0x12C
  .text:00023A24 BL sub_1C294
  .text:00023A28 MOV R4, R0
  .text:00023A2C MOV R0, #0x12C
  .text:00023A30 ORR R0, R0, #2 ;"302, "This version was regist..."
  .text:00023A34 BL sub_20870
  .text:00023A38 MOV R1, R0
  .text:00023A3C MOV R2, R4
  .text:00023A40 ADD R0, SP, #0xD0
  .text:00023A44 BL wsprintfW
  往上查找
  .text:000239C8 ADD R1, SP, #0x10
  .text:000239CC ADD R0, SP, #0x48
  .text:000239D0 BL sub_234D4
  .text:000239D4 CMP R0, #0
  .text:000239D8 BEQ loc_23AB0 ;loc_23AB0 注册失败
  .text:000239DC LDR R5, =unk_78418 ;注册正确
  .text:000239E0 ADD R0, SP, #0x48
  sub_234D4有两处调用,一次是输入注册码时验证,一次是启动时验证,修改sub_234D4返回值就可以了
  sub_234D4
  ........
  .text:00023590 loc_23590 ; CODE XREF: sub_234D4+A4j
  .text:00023590 MOV R0, R7 ;改MOV R0, #1
  .text:00023594 ADD SP, SP, #0x50
  .text:00023598 LDMFD SP!, {R4-R7,PC}
  2.找出TrueFax (Windows Mobile 2003 Phone Edition v2.05 注册码
  注册码比较方式 f(name) == g(code),需要找出g(code)的逆变换
  .text:0002351C MOV R1, R0 ; name
  .text:00023520 STR R3, [SP,#8]
  .text:00023524 MOV R5, #0
  .text:00023528 MOV R6, #0
  .text:0002352C STR R5, [SP,#0xC]
  .text:00023530 MOV R2, #0
  .text:00023534 STR R6, [SP,#0x10]
  .text:00023538 ADD R0, SP, #0x28
  .text:0002353C MOV R7, #0
  .text:00023540 BL sub_230AC ; 变换name -> SP + 0x28 (15位)
  .text:00023544 MOV R1, R4
  .text:00023548 ADD R0, SP, #0
  .text:0002354C BL sub_23280 ; 变换input_regcode ->SP (15位)
  .text:00023550 MOV R3, R7
  .text:00023554
  .text:00023554 loc_23554 ; CODE XREF: sub_234D4+ACj
  .text:00023554 ADD R0, SP, #0
  .text:00023558 LDRH R0, [R3,R0]
  .text:0002355C MOV R1, R0,LSL#16
  .text:00023560 ADD R0, SP, #0x28
  .text:00023564 LDRH R0, [R3,R0]
  .text:00023568 MOV R2, R1,LSR#16
  .text:0002356C ADD R3, R3, #2
  .text:00023570 MOV R1, R0,LSL#16
  .text:00023574 CMP R2, R1,LSR#16 ;比较name和reg.no变换后的结果
  .text:00023578 BNE loc_23590 ;错误
  .text:0002357C CMP R2, #0
  .text:00023580 BNE loc_23554
  .text:00023584 MOV R0, #1 ;正确
  看sub_23280
  .text:00023280 sub_23280 ; CODE XREF: sub_234D4+78p
  .text:00023280 STMFD SP!, {R4-R6,LR} ;
  .text:00023284 SUB SP, SP, #0x30
  .text:00023288 MOV R6, R0
  .text:0002328C MOV R5, R1
  .text:00023290 SUB R3, R5, #2
  .text:00023294
  .text:00023294 loc_23294 ; CODE XREF: sub_23280+20j
  .text:00023294 LDRH R0, [R3,#2]!
  .text:00023298 MOV R1, R0,LSL#16
  .text:0002329C MOVS R2, R1,LSR#16
  .text:000232A0 BNE loc_23294
  .text:000232A4 SUB R0, R3, R5
  .text:000232A8 MOV R1, R0,LSR#1
  .text:000232AC CMP R1, #0xF ;长度判断 应该为15位
  .text:000232B0 BNE loc_232F8
  .text:000232B4 ADD R0, SP, #0x10
  .text:000232B8 ADD R4, SP, #0x10
  .text:000232BC SUB R3, R5, R0
  .text:000232C0
  .text:000232C0 loc_232C0 ; CODE XREF: sub_23280+50j
  .text:000232C0 LDRH R2, [R4,R3]
  .text:000232C4 MOV R0, R2,LSL#16
  .text:000232C8 STRH R2, [R4],#2
  .text:000232CC MOVS R1, R0,LSR#16
  .text:000232D0 BNE loc_232C0
  .text:000232D4 ADD R1, SP, #0x10
  .text:000232D8 ADD R0, SP, #0
  .text:000232DC BL sub_22DF0 ;去掉第1,3,5,7位
  .text:000232E0 ADD R0, SP, #0
  .text:000232E4 BL sub_22EA0
  .text:000232E8 ADD R0, SP, #0
  .text:000232EC BL sub_22AD8 ;1,3,5,7位是否为0 2 7 4
  .text:000232F0 CMP R0, #0
  .text:000232F4 BPL loc_23304 ; 是
  .text:000232F8
  .text:000232F8 loc_232F8 ; CODE XREF: sub_23280+30j
  .text:000232F8 MOV R0, #0 ;返回错
  .text:000232FC ADD SP, SP, #0x30
  .text:00023300 LDMFD SP!, {R4-R6,PC}
  .text:00023304 ; ----------------------------------------------------------------------------------------------
  .text:00023304
  .text:00023304 loc_23304 ; CODE XREF: sub_23280+74j
  .text:00023304 MOV R1, R0
  .text:00023308 ADD R0, SP, #0x10
  .text:0002330C BL sub_231B0 ;变换.text:00023310 ADD R1, SP, #0
  .text:00023314 ADD R0, SP, #0x10
  .text:00023318 BL sub_22D44
  .text:0002331C ADD R0, SP, #0x10
  .text:00023320 SUB R3, R0, R6
  .text:00023324
  .text:00023324 loc_23324 ; CODE XREF: sub_23280+B4j
  .text:00023324 LDRH R2, [R6,R3]
  .text:00023328 MOV R0, R2,LSL#16
  .text:0002332C STRH R2, [R6],#2
  .text:00023330 MOVS R1, R0,LSR#16
  .text:00023334 BNE loc_23324
  .text:00023338 MOV R0, #1
  .text:0002333C ADD SP, SP, #0x30
  .text:00023340 LDMFD SP!, {R4-R6,PC}
  sub_231B0
  .text:000231B0 sub_231B0 ; CODE XREF: sub_23280+8Cp
  .text:000231B0 STMFD SP!, {R4-R11,LR}
  .text:000231B4 SUB SP, SP, #0x18
  .text:000231B8 MOV R10, R0
  .text:000231BC MOV R2, R1
  .text:000231C0 LDR R1, =aTruefax2_0Phon
  .text:000231C4 MOV R3, #0x194
  .text:000231C8 MLA R5, R2, R3, R1
  .text:000231CC MLA R0, R2, R3, R1
  .text:000231D0 ADD R9, SP, #0
  .text:000231D4 MOV R8, #0xB
  .text:000231D8 MOV R7, R5
  .text:000231DC LDR R4, [R0,#0x16C]; 1 5 0 2 6 3 4 7 8 9
  .text:000231E0 MOV R6, R5
  .text:000231E4 MOV R11, #0
  .text:000231E8
  .text:000231E8 loc_231E8 ; CODE XREF: sub_231B0+A0j
  .text:000231E8 LDR R0, [R6,#0xC8];A 5 3 6 2 9 7 8 1 0 4
  .text:000231EC MOV R3, R11
  .text:000231F0 ADD R1, R10, R0,LSL#1
  .text:000231F4 LDRH R2, [R1]
  .text:000231F8 MOV R0, R2,LSL#16
  .text:000231FC MOV R1, R0,LSR#16
  .text:00023200 SUB R2, R1, #0x30
  .text:00023204 CMP R2, R4
  .text:00023208 BEQ loc_23224
  .text:0002320C MOV R1, R5
  .text:00023210
  .text:00023210 loc_23210 ; CODE XREF: sub_231B0+70j
  .text:00023210 ADD R1, R1, #4
  .text:00023214 LDR R0, [R1,#0x16C] ; 1 5 0 2 6 3 4 7 8 9
  .text:00023218 ADD R3, R3, #1
  .text:0002321C CMP R2, R0
  .text:00023220 BNE loc_23210
  .text:00023224
  .text:00023224 loc_23224 ; CODE XREF: sub_231B0+58j
  .text:00023224 LDR R0, [R7,#0x11C] ;3 6 1 2 2 5 8 3 7 4 4
  .text:00023228 SUB R8, R8, #1
  .text:0002322C ADD R7, R7, #4
  .text:00023230 SUBS R1, R3, R0
  .text:00023234 ADDMI R1, R1, #0xA ; 负号
  .text:00023238 ADD R0, R1, #0x30
  .text:0002323C MOV R1, R0,LSL#16
  .text:00023240 MOV R2, R1,LSR#16
  .text:00023244 STRH R2, [R9],#2
  .text:00023248 SUB R6, R6, #4
  .text:0002324C CMP R8, #0
  .text:00023250 BHI loc_231E8
  .text:00023254 ADD R0, SP, #0
  .text:00023258 STRH R11, [SP,#0x16]
  .text:0002325C SUB R3, R0, R10
  .text:00023260
  .text:00023260 loc_23260 ; CODE XREF: sub_231B0+C0j
  .text:00023260 LDRH R2, [R10,R3]
  .text:00023264 MOV R0, R2,LSL#16
  .text:00023268 STRH R2, [R10],#2
  .text:0002326C MOVS R1, R0,LSR#16
  .text:00023270 BNE loc_23260
  .text:00023274 ADD SP, SP, #0x18
  .text:00023278 LDMFD SP!, {R4-R11,PC}
  .text:00023278 ; End of function sub_231B0
  sub_231B0功能:
  按位置A 5 3 6 2 9 7 8 1 0 4取数
  数在1 5 0 2 6 3 4 7 8 9 中位置
  减去3 6 1 2 2 5 8 3 7 4 4 小于0加上A
  u8 pos[] = {1,5,0,2,6,3,4,7,8,9};
  u8 sub[] = {3,6,1,2,2,5,8,3,7,4,4};
  //u8 key_pos[] = {0xa,5 ,3,6,2,9,7,8,1,0,4};
  u8 key_pos[] = {14,9,6,10,4,13,11,12,2,0,8};
  u8 code[15];
  //f(L"wh_cxh") = "048762306414292"
  num[] = {0,8,6,3,6,4,1,4,2,9,2};
  for(int i = 0; i  9)
  temp -= 0xa;
  code[key_pos] = pos[temp];
  }
  code[1] = 0;
  code[3] = 2;
  code[5] = 7;
  code[7] = 4;
  for(int j = 0; j < 15; j++)
  printf("%x", code[j]);
  //209287744639792
  name : wh_cxh
  regcode : 209287744639792
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics