最近心血来潮,想起了以前有个东西叫做家园2,随即下载下来准备回味一番。结果却在搜索中发现与vista和win7不兼容。
  按照网上的方法左试右试发现还是没用,然后我愤怒了,打开了OD。
  载入运行,发现问题在这里:

00400110    83EC 04         sub esp,4    <-执行时访问异常。
00400113    50              push eax
00400114    8B4424 08       mov eax,dword ptr ss:[esp+8]
00400118    894424 04       mov dword ptr ss:[esp+4],eax
0040011C    58              pop eax
0040011D    60              pushad
0040011E    8B4424 20       mov eax,dword ptr ss:[esp+20]
00400122    BA 0C094000     mov edx,offset Homeworld2.0040090C
00400127    33DB            xor ebx,ebx
00400129    EB 14           jmp short Homeworld2.0040013F
0040012B    390413          cmp dword ptr ds:[edx+ebx],eax
0040012E    75 0C           jne short Homeworld2.0040013C
00400130    8B4413 FC       mov eax,dword ptr ds:[edx+ebx-4]
00400134    8B00            mov eax,dword ptr ds:[eax]
00400136    894424 20       mov dword ptr ss:[esp+20],eax
0040013A    EB 09           jmp short Homeworld2.00400145
0040013C    83EB 08         sub ebx,8
0040013F    833C13 00       cmp dword ptr ds:[edx+ebx],0
00400143  ^ 75 E6           jne short Homeworld2.0040012B
00400145    61              popad
00400146    C3              retn

  为什么会这样呢?我们首先想既然破解是这么发布的,所以它这段代码肯定不会有问题。然后结合网上说DEP的问题,我觉得它唯一的问题就是这段代码是写在了PE头部区域中造成的。
  大家都知道在xp时代,PE头里面写的代码是可以无忧运行的,堆栈里面的同样也没有问题。但是这时候DEP出现了,不允许将数据区域作为代码执行,所以这个时候上面这些写在PE头里面的代码就无法运行了。
  Address = 00400000
  Size = 00001000 (4096.)
  Owner = Homeworld2 00400000 (self)
  Section =
  Contains = PE header
  Type = Img  01001002
  Access = R
  Initial access = RWE CopyOnWr
  如上所写,我们看见PE头部区域被严格的保护成了只读模式,没有执行的权限。
  这是我们就有思路了,我们可以将PE头改成RE(可执行可读),或者我们将上面那段代码搬迁到.text区段中。
  很明确的说,结果是可行的,但是为什么我没用呢?这是因为伟大的win7_x64+OD2.0完全搜索不到API的名字……这使我感觉很悲剧=。=

--------------------------------------------------------我是纯洁的分割线---------------------------------------------------------

  我们将这一小段代码搬迁到.text区段中的空白数,从00694A6A开始。然后仔细的阅读这一段代码我们发现它引用了0040090C这么一个地址,这里是是什么呢?结合代码,我们认为它应该是一个表。我们按Ascii dump模式看看:

00400638   006958D0  Xi.  ; <&memory.MemCRTFree>
0040063C   00422699  &B.  ; RETURN from Homeworld2.00400110 to Homeworld2.00422699
00400640   00695244  DRi.  ; <&fileio.RamStream::Attach>
00400644   0041D41D  A.  ; RETURN from Homeworld2.00400110 to Homeworld2.0041D41D
00400648   006958CC  Xi.  ; <&memory.MemCRTAlloc>
0040064C   0041CDC4  A.  ; RETURN from Homeworld2.00400110 to Homeworld2.0041CDC4
00400650   0069585C  \Xi.  ; <&msvcr70.wcslen>
00400654   0041C90C  .A.  ; RETURN from Homeworld2.00400110 to Homeworld2.0041C90C
………………
004008F4   00404497  D@.  ; RETURN from Homeworld2.00400110 to Homeworld2.00404497
004008F8   006958CC  Xi.  ; <&memory.MemCRTAlloc>
004008FC   00403940  @9@.  ; RETURN from Homeworld2.00400110 to Homeworld2.00403940
00400900   00695F5C  \_i.  ; <&lua.lua_tonumber>
00400904   004035B1  5@.  ; RETURN from Homeworld2.00400110 to Homeworld2.004035B1
00400908   006958D0  Xi.  ; <&memory.MemCRTFree>
0040090C   00401DEB  @.  ; RETURN from Homeworld2.00400110 to Homeworld2.00401DEB

  这确实是一张表,那么我们就不用动了,因为查表的时候只有读的操作,这样是不会被和谐的。
  然后新问题,我们还要将代码段中所有指向400110的call改过来。怎么办,例遍代码来找?太麻烦了。我们结合查表的代码来看这张表。很明显的以2个DWORD为一组,第一个DWORD为需要跳转到的API,第二个为返回的地址。
  这样就简单了,我们写一小段代码取返回地址,然后计算一下调用的距离,然后写入一下就解决了。
  或者,你可以更进一步的,将这些调用全部还原成call []的形式。