apk反汇编之smali语法

类型

Dalvik的字节码中拥有两个主要的类型:基类和引用类型。引用类型

引用类型是对象和数组,其他的一切都是基类

基类被一个简单的字符描述。我没有提出这些缩写词———他们实际以字符串的形式存储于dex文件中

他们被定义与dex格式网页文档中(在AOSP库中的路径是dalvik/docs/dex-format.html)

V  空类型—仅仅可以用来作为返回类型

Z  Boolean 布尔型

B  Byte字节型

S  Short短整型(16位)

C  Char字符型

I  Int 整形

J  long (64 bits)长整型(64位)

F  Float浮点型

D  double (64 bits)双精度型(64位)

对象采用这样的形式Lpackage/name/ObjectName—开始的L表明这是一个对象类型,package/name/就是该对象,对象名是是对象的名称,并且分号表明对象名的结束。这个等同于java语言中的package.name.ObjectName结构,举个更具体的例子,“ Ljava/lang/String;”就等同于java语言的“java.lang.String”。数组采用[I的形式—这代表一个一维整形数组就像java语言中的int[]。而多维数组,你简单的增加字符‘[’就行了,例如[[I=int[][](最大的维度是255).你也可以使用数组对象,例如[Ljava/lang/String就是一个字符串数组。

方法

方法总是被定义为一个非常复杂的包括方法,方法名,参数类型和返回值的形式。

所有的这些信息被要求对于虚拟机而言可以找到正确的方法并且能够表现字节码上的静态分析(为了确认挥着选择最优化)。他们采用如下形式

Lpackage/name/ObjectName;->MethodName(III)Z

在这个例子中,你应该识别出“ Lpackage/name/ObjectName; 是一个类, MethodName明显是一个方法名,(III)Z是方法的签名,‘III’在这个例子中是三个整形参数,Z是表示返回一个布尔类型的返回值。

They take the form

Lpackage/name/ObjectName;->MethodName(III)Z

In this example, you should recognize Lpackage/name/ObjectName; as a type. MethodName is obviously the name of the method. (III)Z is the method's signature. III are the parameters (in this case, 3 ints), and Z is the return type (bool).

方法的参数一个接一个的列举在右边,中间没有分号。给出一个更复杂的例子:

method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;

在java语言中,他应该是这样的

String method(int, int[][], int, String, Object[])

域同样的被指定为一个冗长的包括域,域名,域类型的形式。此外,它也允许虚拟机找到正确的域来表现字节编码的静态分析。

它们采用如下形式:

Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;

这相当的不言自明—分别表示域名,域名和域类型

在dalvik字节码中,寄存器总是32位可以存放任何类型的值,2个寄存器可以用来存放64位类型(长整形和双精度型)

指定方法中的寄存器数字

这里有两种办法来指定一种方法中的多个寄存器。寄存器直接指定方法中的寄存器总数,或者区域变量直接指定方法中的非参数寄存器数。寄存器总数包括方法中参数所需的所有寄存器。

多少参数传入方法

当一个方法被调用,方法中的参数被放置到最近的几个寄存器。如果一个方法拥有两个参数和五个寄存器,这些参数会被存放到最后的两个寄存器V3和V4.

动态方法的第一个参数总是被调用的第一个对象,例如让你写一个动态方法 LMyObject;->callMe(II)V,这个方法有两个整形参数,但是还有一个隐含的参数‘LMyObject’在两个整形参数之前,所以总共有三个参数在这个方法中。

我们假设你在一个方法中制定了5个寄存器(v0-v4),既不是寄存器5管理也不是本地寄存器2管理(2个本地寄存器和3个参数寄存器)

当该方法被调用后,被调用的对象是V2,第一个整型参数是V3,第二个是V4。在静态方法中也是同样的,除非没有隐含的this指针参数。

寄存器名称

对于寄存器这里有两种命名方案—标准的V命名方案和对于参数寄存器的P命名方案。

以p命名的第一个寄存器就是方法中的第一个参数寄存器,所以让我们回到之前的总共拥有5个寄存器其中3个参数的例子。下表中显示了为每个寄存器的标准v命名,紧接着是为参数寄存器的p命名

v0     the first local register

第一个本地寄存器

v1     the second local register

第二个本地寄存器

v2  p0  the first parameter register

第一个参数寄存器

v3  p1  the second parameter register

第二个参数寄存器

v4  p2  the third parameter register

第三个参数寄存器

你可以通过每个名称类参照参数寄存器—这没有什么两样

p命名方案是作为一个实用的内容被引入的来解决编辑smali编码中的共同的难点。

假设你有一个已经存在的方法拥有一定数目的参数,你想增加一些代码到这个方法,你会发现你需要一个额外的寄存器。

你会想,没什么大不了的,我仅仅在寄存器管理中增加寄存器数目就可以了。但是不幸的是,这并不容易。请记住方法中的参数是寄存在最近的寄存器中的。如果你增加寄存器数—你会改变方法参数的在寄存器中的输入。所以你就不得不改变寄存器管理并且重编号参数寄存器

但是如果是你在方法中使用p命名模式来引用参数寄存器,你可以很容易的改变方法中的寄存器数而不必担心重编号任何存在的寄存器。

注意:默认baksmali对于参数寄存器使用p命名模式来命名。如果你因为某些原因不适用p命名而强制使用V命名模式,你可以使用-p/–no-parameter-registers来选择。

Long/Double values

长整型/双精度型值

鉴于以前提到过,长整型和双精度型(用J和D分别代表)的基本单元是64位,需要使用2个寄存器。

当你引用方法中的参数时必须牢牢记住。

例如,我们夹着你拥有一个非静态的方法LMyObject;->MyMethod(IJZ)V。方法的参数是“LMyObject;”,整形,长整形和布尔型。所以在这个方法中会要求五个寄存器来存放所有的参数。并且,当你以后调用这个方法时,你为了调用该指令不得不在寄存器列表中指定两个寄存器来存放任何64位的参数

Baksmali现在可以来反编译odex文件,并且选择性的deodex他们。

注意:本页说明仅仅应用于baksmali v0.96-v1.1。v1.2以上版本开始不再要求deodexrant.随心版本说明可以在http://code.google.com/p/smali/wiki/DeodexInstructions找到。

详细介绍

他要求deodexrant 的帮助,这是一个较小的可以在手机上运行并且连接到dalvik酷的二进制文件

他的目的在从正在运行的dalvik中获得类似寄存器表,域偏移量等信息提供给baksmali

Deodexrant的语法如下:

deodexerant <odex_file> <port>

接着baksmali拥有一个新的选项来告诉deodex文件,语法如下:

baksmali -x <host>:<port> <odex_file>

你也可以用-x :<port> 作为 –x localhots:<port>的快捷方式

主要的事情你必须记住的是当你将文件deodex化的时候,当odex文件被创建的时候你必须运行一些“bootclasspath”jar文件

最容易满足的这个的是当你尝试deodex的时候运行在硬件上。如果你需要从不同的硬件上deodex一些文件时也有可能改变根目录环境,但是我会将它作为一个练习留给读者

我们假设你正在运行一个基于美国移动商的官方版本的rom,并且苹果程序在/system/app目录下被deodex。一个deodex交互会像如下情形:

adb push deodexerant /data/local

adb shell chmod 755 /data/local/deodexerant

adb forward tcp:1234 tcp:1234

adb pull /system/app/Calculator.odex .

adb shell /data/local/deodexerant /system/app/Calculator.odex 1234 &

java -jar baksmali.jar -x :1234 Calculator.odex

你会活得一系列的smali文件在外层目录下,准备好用smali反编译这些dex文件。

注意我如何适应adb来通过usb来通信。如果你试着用wifi这个将会很慢。

鉴于baksmali向deodex制造了大量短小的同步请求,潜在上抑制了性能,所以usb连接比wifi用时更少

Troubleshooting

解决问题

When deodexing, there are several common issues you may run into.

当进行deodex的时候,可能会有几个问题你会遇上

The most common, which is almost guaranteed to happen if you're deodexing an entire build, is an error which is something like "Cannot find class Lfoo/bar; for common superclass lookup".

最常见保证很有可能发生的是如果你deodex一个完整的构造,会出现一个类似的错误“Cannot find class Lfoo/bar; for common superclass lookup”。

这是由于当odex文件拥有在标准的BOOTCLASSPATH一个额外的附属物超出了jars的范围

This is caused when the odex file has an additional dependency, beyond the jars in the normal BOOTCLASSPATH. To resolve the issue, you need to find which jar contains the class mentioned in the error message, and then add that to the BOOTCLASSPATH environment variable (on the phone/device/emulator) before running deodexerant.

为了解决这个问题,你需要找到那个包含错误信息提示的那个类的jar文件并且在运行deodexrant前将它添加到BOOTCLASSPATH环境变量中。

You can usually guess which jar it is from the class name, but if not, you can disassemble the jars and find which one has that class.

通常你可以根据类名来猜测是哪个jar,如果不行,你可以反编译jars然后找出包含该类的jar

Once you find the extra dependency, let's say /system/framework/com.google.android.maps.jar (which is one that is commonly needed), the deodexerant command would be

(on linux/mac)

一旦你找到了该额外的附属,我们就假设它是/system/framework/com.google.android.maps.jar

(这是普遍被需求的一个jar),那么deodexrant命令就如下(linux和mac平台)

adb shell BOOTCLASSPATH=\$BOOTCLASSPATH:/system/framework/com.google.android.maps.jar deodexerant blah.odex 1234 &

Windows平台

adb shell BOOTCLASSPATH=$BOOTCLASSPATH:/system/framework/com.google.android.maps.jar deodexerant blah.odex 1234 &

________________________________________

另外的一件你可能遇到的事实堆溢出。错误提示类似“java.lang.OutOfMemoryError: Java heap space”。解决他的办法是你可以增加java参数-Xmx512m来增加堆到512Mb。当然如果需要你也可以增加到更大。如果你正在使用类似“java -jar baksmali.jar”来运行baksmali,可以用如下指令来代替

java -Xmx512m -jar baksmali.jar -x :1234 blah.odex

如果你正在使用封装脚本

baksmali -JXmx512m -x :1234 blah.odex

________________________________________

另外一件事是发生在一些平台上(个人认为尤其是windows平台)的堆溢出。错误提示类似“java.lang.StackOverflowError”。错误的堆栈轨迹很可能是包含了类似"at org.jf.dexlib.Util.DeodexUtil$insn.propagateRegisters(DeodexUtil.java:1396)"的说明。

为了修正这个错误,你可以用-Xss10m指令来增加堆空间

java -Xss10m -jar baksmali.jar -x :1234 blah.odex

or

baksmali -JXss10m -x :1234 blah.odex

超级网站整站下载器V4正式版 破文又一篇

上次破解了V2.5版  http://www.ccc5.cc/1245.html

今天想下载个静态网页,找了好几个软件都不满意,找来找去又找到了这http://www.onlinedown.net/soft/118426.htm

发现这货居然升级到了V4.0版  而且运行就要登陆  还增加了什么SEO用户  站群用户….

正好好久没搞破解了  继续拿来练练手

查壳依旧和原来一样结果

E Language -> WuTao   * Sign.By.fly *

依旧舍不得加壳

易语言独立编译的   好吧  对付这种软件的老规矩了

OD载入—-找字符串“error”——下段该字符串上面的第一个”je”——–F9跑起来,断在了je处———–Alt+E查看加载的模块  双击krnln.fnr模块

————–Ctrl+B搜索FF55FC—————–下断找到的第一个CALL————F9来到CALL——F7跟进

来到程序的关键段了

开始找关键地方了

查找字符串  留意“用户密码错误”、“商业用户”之类的字眼  找到其上的关键跳下断

首先我找到这个三个跳

 

00533D2D    A3 BC044D01     mov dword ptr ds:[14D04BC],eax
00533D32    68 BC044D01     push 14D04BC
00533D37    E8 C3340000     call 超级网站.005371FF
00533D3C    8945 E4         mov dword ptr ss:[ebp-1C],eax
00533D3F    837D E4 01      cmp dword ptr ss:[ebp-1C],1
00533D43    0F85 F30A0000   jnz 超级网站.0053483C        ; 大跳
00533D49    68 01000000     push 1
00533D4E    68 02000000     push 2
00533D53    68 BC044D01     push 14D04BC
00533D58    E8 13350000     call 超级网站.00537270
00533D5D    8945 E8         mov dword ptr ss:[ebp-18],eax
00533D60    8B45 FC         mov eax,dword ptr ss:[ebp-4]
00533D63    50              push eax


00533DE5    B8 01000000     mov eax,1
00533DEA    EB 02           jmp short 超级网站.00533DEE
00533DEC    33C0            xor eax,eax
00533DEE    85C0            test eax,eax
00533DF0    0F84 110A0000   je 超级网站.00534807     ; 这也是个大跳
00533DF6    68 01000000     push 1
00533DFB    68 0A000000     push 0A
00533E00    68 BC044D01     push 14D04BC
00533E05    E8 66340000     call 超级网站.00537270
00533E0A    8945 E8         mov dword ptr ss:[ebp-18],eax
00533E0D    68 04000080     push 80000004


00533F56    E8 E86AFEFF     call 超级网站.0051AA43
00533F5B    8945 EC         mov dword ptr ss:[ebp-14],eax
00533F5E    837D EC 01      cmp dword ptr ss:[ebp-14],1
00533F62    0F85 1F020000   jnz 超级网站.00534187     ; 这还是个大跳
00533F68    68 01000000     push 1
00533F6D    68 05000000     push 5
00533F72    68 BC044D01     push 14D04BC
00533F77    E8 F4320000     call 超级网站.00537270

均是大跳,如果实现则把下面的“商业用户”跳过去了,下断它,继续寻找~~~

还找到几个,由于我试验过,均没什么影响,就不提了

然后F9把程序跑起来,跑了好久才跑起来,期待的启动界面没出来

给我弹出个框框说

初始化失败,可能一下原因\n服务器地址不对,通讯密保不对,或者软件号不对

,可能是服务器挂了吧!!!尝试进入官网,果然进不去,难怪程序跑了半天才跑起来

好吧,找到关键的地方,把错误提示JMP过去,顺便把上面链接服务器的CALL都NOP掉~~~不然启动程序都要花费几十秒

 

00532F9C    6A 01           push 1
00532F9E    B8 52BA4100     mov eax,超级网站.0041BA52                 ; POST
00532FA3    8945 FC         mov dword ptr ss:[ebp-4],eax
00532FA6    8D45 FC         lea eax,dword ptr ss:[ebp-4]
00532FA9    50              push eax
00532FAA    68 8039F100     push 0F13980 ;一大堆的PUSH 把下面的CALL看不顺眼的都NOP掉吧
00532FAF    B8 29BC4100     mov eax,超级网站.0041BC29                    ; 515236498
00532FB4    8945 F8         mov dword ptr ss:[ebp-8],eax
00532FB7    8D45 F8         lea eax,dword ptr ss:[ebp-8]
00532FBA    50              push eax
00532FBB    B8 33BC4100     mov eax,超级网站.0041BC33           ; http://www.oferry.com/vip/AppEn.php
00532FC0    8945 F4         mov dword ptr ss:[ebp-C],eax
00532FC3    8D45 F4         lea eax,dword ptr ss:[ebp-C]

改好重新F9

登录框出来鸟。

 

 

 

 

 

 

 

 

选择3.0老用户,然后随便输入帐号密码 点登陆

成功断在了我们下的断点上,依据情况自己把跳给改了,别让它把关键地方跳过去

然后F9

好吧就是这个效果

破解了的下载地址就不提供了

 

各种保护壳易语言的SDK代码

ZProtect

//Code_Confusion 是代码乱序加密标记,允许您选择一部分被乱序的代码
置入代码 ({ 235, 8, 83, 84, 95, 83, 84, 65, 82, 84 }) ' Code_Confusion标记开始
置入代码 ({ 235, 8, 83, 84, 95, 83, 84, 69, 78, 68 }) ' Code_Confusion标记结尾
//Code_Elimination 是代码清除标记,允许您选择一部分代码在运行后从内存中删除;使用此标记的目的是为了防止破解者从内存中转储出完整的程序代码。
置入代码 ({ 235, 8, 79, 67, 95, 83, 84, 65, 82, 84 }) ' Code_Elimination标记开始
置入代码 ({ 235, 8, 79, 67, 95, 79, 67, 69, 78, 68 }) ' Code_Elimination标记结尾
//Decode_onExec 是动态解码标记,允许您选择一部分只在执行时才解密的代码段;这部分代码仅在需要执行时才解码,执行前和执行后均处于加密状态
置入代码 ({ 235, 8, 68, 89, 95, 83, 84, 65, 82, 84 }) // Decode_onExec标记开始
置入代码 ({ 235, 8, 68, 89, 95, 68, 89, 69, 78, 68 }) // Decode_onExec标记结尾
//Decode_onReg 是注册解码标记,允许您选择一部分使用有效密钥才解密的代码;如果注册密钥不正确,那么这部分代码将永远处于加密状态。通俗地讲,这部分代码仅在注册版中执行
//源代码中可以使用任意数量的 Decode_onReg 标记,但是这些代码段在执行时会同时解密。注册解码标记主要用于激活未注册版中被限制的功能,使之注册成为完整版。
置入代码 ({ 235, 8, 82, 68, 95, 83, 84, 65, 82, 84 }) // Decode_onReg标记开始
置入代码 ({ 235, 8, 82, 68, 95, 82, 68, 69, 78, 68 }) // Decode_onReg标记结尾
//Zprotect_VM 是虚拟机加密标记,允许您选择一部分代码放到虚拟机中运行;虚拟机的指令系统是完全不同于现有的 x86 指令,可以有效阻止代码还原及分析
置入代码 ({ 235, 8, 86, 77, 95, 83, 84, 65, 82, 84 }) // Zprotect_VM标记开始
置入代码 ({ 235, 8, 86, 77, 95, 86, 77, 69, 78, 68 }) // Zprotect_VM标记结尾
———–适用于ZProtect V1.4.9.0版本———

为某些软件加皮肤

有些软件的默认界面实在太搓了   但苦于软件作者的审美观与软件制造水平实在不成正比  各位童鞋只能默默的忍

今天在一蓑烟雨论坛闲逛偶然发现了这个帖子  故转来

需准备工具 (猛戳下面去下载)

LordPE Deluxe

然后需要的俩dll和she皮肤我会打包     更多she皮肤请自行百度

开工吧

把俩DLL程序和那个skinh.she皮肤放到需要修改皮肤的EXE文件目录下

先运行EXE  开始是没效果(有点废话)

然后运行上面告诉你下载的工具

按下图箭头所示步骤操作

然后按照如图填写相应的导入信息

点完加号后确认  然后关掉导入表  点保存确认  再来个保存确认就OK了

再运行EXE看看

好了  具体就是这样了

如果想要更换别的皮肤  只要去百度搜SHE皮肤下载  重命名为 skinh.she 覆盖现在这个就可以了  

下面附上我收藏的一些she皮肤以及两个调用皮肤的DLL

 

 

如果您想自己更换别的DLL接口函数名并且有点C++基础的话  这里附上skin.dll的C++源码

感谢一蓑烟雨 vienna vienna http://www.unpack.cn/thread-47495-1-4.html 的源码

 


#include
#include "SkinH.h"
#pragma comment (lib,"SkinH.lib")

extern "C" _declspec(dllexport) void Hello();

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
Hello();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
SkinH_DetachEx(NULL);
break;
}

return TRUE;
}

void Hello() {
#include
#include "SkinH.h"
#pragma comment (lib,"SkinH.lib")

extern "C" _declspec(dllexport) void Hello();

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
{
switch(ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
Hello();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
SkinH_DetachEx(NULL);
break;
}

return TRUE;
}

void Hello() {
//皮肤效果都往这里加~~
SkinH_Attach();
}

超级网站整站下载器2.5正式版 破文一篇

     废话不多说  直接开始

软件名:超级网站整站下载器2.5正式版

软件下载: http://www.onlinedown.net/soft/118426.htm

软件说明

【概括介绍】

国内最好用的网站整站下载工具。

【基本介绍】

一、可打开,保存工程文件,方便您下次使用

二、下载各种类型的文件,任务列表将显示地址和文件类型,不同的文件类型以不同的图标显示

三、顶部为,任务列表框,显示取回的所有任务列表。底部为网页文件任务列表框,仅显示取回的网页

四、两个任务列表框都可以设置显示和隐藏,当您觉得速度有点慢时,可隐藏一个列表框,速度会加速起来的哦..

五、独有的 JSP,PHP网页分析。最大化的帮您完全复制一个网站。

六、设置列表里,可设置是否按照网站目录结构取回。不选中,所有文件将全部下载到当前目录内。建议选中

七、单击右上角关闭按钮,程序将缩小到托盘运行,此时下载任务更快更方便。

价格有点贵  而且不买的话那些实用功能根本没法用

 

PEid查壳结果
E Language -> WuTao   * Sign.By.fly *
没加壳  是人都喜欢啊
看来是非独立编译的易语言   据说独立编译的会显示VC++6.0
 
OD载入 直接到了00401000
 
代码如下
 
 


00401000 >/$ E8 06000000 call 超级网站.0040100B
00401005 |. 50 push eax ; /ExitCode
00401006 \. E8 BB010000 call ; \ExitProcess
0040100B /$ 55 push ebp
0040100C |. 8BEC mov ebp,esp
0040100E |. 81C4 F0FEFFFF add esp,-0x110
00401014 |. E9 83000000 jmp 超级网站.0040109C
00401019 |. 6B 72 6E 6C 6>ascii "krnln.fnr",0
00401023 |. 6B 72 6E 6C 6>ascii "krnln.fne",0
0040102D |. 47 65 74 4E 6>ascii "GetNewSock",0
00401038 |. 53 6F 66 74 7>ascii "Software\FlySky\"
00401048 |. 45 5C 49 6E 7>ascii "E\Install",0
00401052 |. 50 61 74 68 0>ascii "Path",0
00401057 |. 4E 6F 74 20 6>ascii "Not found the ke"
00401067 |. 72 6E 65 6C 2>ascii "rnel library or "
00401077 |. 74 68 65 20 6>ascii "the kernel libra"
00401087 |. 72 79 20 69 7>ascii "ry is invalid!",0
00401096 |. 45 72 72 6F 7>ascii "Error",0

从入口代码也可知为非独立编译
 
查找ASCII码
双击字符串 “Error”
F2下段上面的那个je 然后F9运行程序 目的是为了让程序加载krnln.fnr模块
 
Alt+E查看加载的模块  双击krnln.fnr模块  来到相应的代码段
 
Ctrl+B搜索FF55FC
在找到的第一个CAll下断
F7进CALL
 
代码如下
 
 


005CED72 55 push ebp
005CED73 8BEC mov ebp,esp
005CED75 81EC 1C000000 sub esp,0x1C
005CED7B C745 FC 0000000>mov dword ptr ss:[ebp-0x4],0x0
005CED82 8965 F8 mov dword ptr ss:[ebp-0x8],esp
005CED85 68 59444000 push 超级网站.00404459 ; 超级网站整站下载器2.5正式版
005CED8A 68 00000000 push 0x0
005CED8F B8 03000000 mov eax,0x3
005CED94 E8 254A0200 call 超级网站.005F37BE
005CED99 3965 F8 cmp dword ptr ss:[ebp-0x8],esp
005CED9C 74 0D je short 超级网站.005CEDAB

 

 

 
然后搜字符串吧
 
中文搜索引擎, 条目 68
 地址=005CC22E
 反汇编=push 超级网站.00403739
 文本字符串=欢迎您来到注册用户
 
 
关键跳就在下面了 拉动水平滚动条看我的注释
 
 


005CC23D 85C0 test eax,eax
005CC23F 75 05 jnz short 超级网站.005CC246
005CC241 B8 83354000 mov eax,超级网站.00403583
005CC246 50 push eax
005CC247 68 04000000 push 0x4
005CC24C BB 48010000 mov ebx,0x148
005CC251 E8 56750200 call 超级网站.005F37AC
005CC256 83C4 34 add esp,0x34
005CC259 8945 F4 mov dword ptr ss:[ebp-0xC],eax ; 当然还可以修改这里为别的寄存器 因为下面的内存数据是由这个eax传递过去的
005CC25C 837D F4 00 cmp dword ptr ss:[ebp-0xC],0x0 ; 当然 最求一字节爆破的也可以把ebp-0xC修改成ebp-0xB或别的
005CC260 0F8E 62010000 jle 超级网站.005CC3C8 ; NOP掉这句 为什么呢 翻翻下面就知道 他把下面的商业用户都跳过去了
005CC266 6A 00 push 0x0
005CC268 68 0060C000 push 0xC06000
005CC26D 6A FF push -0x1
005CC26F 6A 10 push 0x10
005CC271 68 7E000116 push 0x1601007E

修改完成记得转存
看看效果
完成  收工

PEDIY之—-给记事本添加额外功能

作 者: newjueqi

链 接: http://bbs.pediy.com/showthread.php?t=81208

=========原创信息还是必须保留滴  敬重技术达人=============

 

 具体的思路:其实自动保存功能就是程序隔一段时间保存一次,而记事本程序是自带了保存功能的,所以只要编程安装一个记时器,每隔一段时间模拟点击“保存菜单”,就能实现自动保存,最后退出时把记时器撤销。

首先,用eXeScope给记事本增加两个菜单项“自动保存”“关闭自动保存”,如图1所示:

 

图1

其中,“自动保存”的菜单ID是8 ,“关闭自动保存” 的菜单ID是13。

完成后的菜单选项如图2所示:

 图2

本次修改要用到3个window API函数: SetTimer, KillTimer , SendMessageA, 这3个API没包括在记事本的输入表里,所以要用LordPE 在输入表里增加这3个API。

用LordPE打开记事本程序,依次选择Direction->输入表的“…”按钮¬->点击右键->add import,出现如图3的界面,就可以在输入表里增加新的API

图三

完成后就新增了一个区段Slivana如图4,放的就是新的IID数据,如图4所示

图4

添加完新的API后又有一个新的问题了,那就是要确定新的API地址,这个在PEDIY的过程中是要自己解决的,而平时是编译器帮忙的。获得API地址有两个方法:

(1)直接查看新增的IID数据,载入程序后在命令行打入d 1013000,如图5所示:

图5

 

从IAT与INT的对应关系可得
SetTimer的地址=[0101302C ]
MessageBoxA的地址=[ 01013030]
KillTimer的地址=[01013034 ]
 
(2) 在OD中,按Ctrl+N组合键,就能看到API地址的位置,如图6的红框部分所示
图6
 由于PEDIY一般都是在默认的窗口过程前先处理我们定义的消息,所以接下来分析一下记事本程序的流程,看看记事本的窗口过程地址。众所周知,在一个标准的窗口程序中,必须要注册窗口类,函数原型如下:
ATON RegisterClassEx(CONST WNDCLASSEX *Ipwcx);
 
其中WNDCLASSEX *Ipwcx是个结构体指针,定义如下:
WNDCLASSEX STRUCT DWORD 
       cbSize DWORD ? 
       style DWORD ? 
       lpfnWndProc DWORD ? 
       cbClsExtra DWORD ? 
       cbWndExtra DWORD ? 
       hInstance DWORD ? 
       hIcon DWORD ? 
       hCursor DWORD ? 
       hbrBackground DWORD ? 
       lpszMenuName DWORD ? 
       lpszClassName DWORD ? 
       hIconSm DWORD ? 
WNDCLASSEX ENDS 
 
lpfnWndProc就是窗口过程的地址,所以我们只需要在RegisterClassEx下中断,就能知道窗口过程的地址,在OD中如图7所示:
图7
 
从图7可看到1003429就是系统默认的窗口过程的地址。
 在开始写代码前我们先简单回顾一下的windows的窗口过程函数和一般函数调用的过程,因为我们在后面的实际编码过程中必须要对这两个方面的知识有一定的了解。
窗口过程的原型为
wondowPrco proc hwnd,uMsg, wParam, lParam
 
hwnd: 窗口的句柄,可通告CreateWindowEx函数的返回值获取
uMsg: 消息的标识,一般以WM开头
wParam, lParam: 消息的两个参数
 当我们点击某个菜单后就产生了WM_COMMAND消息,对于菜单引发的的WM_COMMAND消息, lParam 的值为0,wParam的低16位是命令ID,高16位是通知码,菜单消息的通知码是0。
当调用一个_stdcall函数的时候,首先是函数的参数按从右到左的顺序入栈,然后是函数的返回地址入栈,一般函数调用的开始有“push ebp  mov ebp,esp”这句,所以我们进入窗口过程后就能得到类似于图8的堆栈结构
图8
 
0006FDE0  /0006FE0C    ; ebp的值
0006FDE4  |77D18734   ; 返回到 user32.77D18734,返回地址值
0006FDE8  |00100618    ;窗口的句柄
0006FDEC  |00000111    ;WM_COMMAND的16进制值,可查阅WinUser.h文件获得
0006FDF0  |00000008    ;wParam,“自动保存”的菜单ID是8
0006FDF4  |00000000    ;lParam,

 

 

 

由此可知,[ebp+c]是消息的类型,[ebp+10]是wParam参数,获取菜单的ID就需要知道wParam参数。

  另外还有一个问题要解决,SetTimer和KillTimer这两个API函数的参数中必须要传入窗口句柄作为参数,但窗口句柄怎么找呢?我们知道,在用CreateWindowExW函数创建窗口后会返回一个窗口句柄,在OD里对CreateWindowExW下断点,中断后代码如图9:

图9

从红框部分可知,窗口句柄保存在地址[1009830]。

 

我们要模拟点击“保存”菜单,可以通过SendMessageW函数向窗口过程发送菜单消息,SendMessageW的原型如下:
LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
参数:
hWnd就是窗口句柄,从上面分析可知,保存在[1009830]地址上。
Msg是要发送的消息类型,查阅WinUser.h文件可知,WM_COMMAND为0x111
wParam的低16位是命令ID,高16位是通知码,菜单消息的通知码是0,通过eXeScope可查知“保存”的菜单ID 为3,所以wParam参数为3。
lParam,对于菜单消息来说,为0。
  接下来就是实际的代码,本人选择在0100874F处添加代码,所以要把图7红框部分的1003429改为0100874F。
 
下面是写入的代码:
0100874F   .  55            push    ebp
01008750   .  8BEC          mov     ebp, esp
01008752   .  60            pushad  
01008753   .  817D 0C 11010>cmp     dword ptr [ebp+C], 111  ;先比较消息的类型,看是否WM_COMMAND, 如果是WM_COMMAND的话再检查wParam参数进一步确定是哪个菜单的消息
0100875A   .  75 0C         jnz     short 01008768    ;如果不是WM_COMMAND消息的话就检查是否WM_TIMER或WM_CLOSE消息
0100875C   .  837D 10 08    cmp     dword ptr [ebp+10], 8  ;比较菜单的ID号,看是否“自动保存”的菜单ID
01008760   .  74 1C         je      short 0100877E    ;不是的话就跳去检查其它的消息类型
01008762   .  837D 10 0D    cmp     dword ptr [ebp+10], 0D    ;比较菜单的ID号,看是否“关闭自动保存”的菜单ID
01008766   .  74 48         je      short 010087B0    ;不是的话就跳去检查其它的消息类型
01008768   >  817D 0C 13010>cmp     dword ptr [ebp+C], 113  ;比较消息的类型是否是WM_TIMER消息,响应定时器消息
0100876F   .  74 5F         je      short 010087D0    ;不是的话就跳去函数的结束清场工作
01008771   .  837D 0C 10    cmp     dword ptr [ebp+C], 10  ;比较消息的类型是否是WM_CLOSE消息,闭关时要先撤销定时器
01008775   .  74 39         je      short 010087B0    ;不是的话就跳去函数的结束清场工作
01008777   >  61            popad
01008778   .  5D            pop     ebp
01008779   .^ E9 ABACFFFF   jmp     01003429  ;跳回原来记事本的消息循环
0100877E   >  C605 20890001>mov     byte ptr [1008920], 1  ;标记已使用自动保存功能
01008785   .  6A 00         push    0          ; /Timerproc = NULL
01008787   .  68 60EA0000   push    0EA60      ; |Timeout = 60000. ms
0100878C   .  6A 01         push    1           ; |TimerID = 1
0100878E   .  FF35 30980001 push    dword ptr [1009830]     ; |hWnd =  [1009830],在CreateWindowExW后保存窗口句柄的地址
01008794   .  FF15 2C300101 call    dword ptr [<&user32.SetTimer>]   ; \SetTimer
0100879A   .  6A 00         push    0                 ; /Style = MB_OK|MB_APPLMODAL
0100879C   .  68 00DB0001   push    0100DB00         ; |Title = "Note"
010087A1   .  68 10DB0001   push    0100DB10          ; |Text = "AutoSave Start!"
010087A6   .  6A 00         push    0               ; |hOwner = NULL
010087A8   .  FF15 30300101 call    dword ptr [<&user32.MessageBoxA>>; \MessageBoxA  ;提示已使用自动保存功能
010087AE   .^ EB C7         jmp     short 01008777  ;跳去函数结束清场
010087B0   >  803D 20890001>cmp     byte ptr [1008920], 0  ;先比较是否已启动定时器
010087B7   .^ 74 BE         je      short 01008777    ;如果没启动定时器就跳去函数结束清场
010087B9   .  C605 20890001>mov     byte ptr [1008920], 0  ;把启动定时器的标记恢复
010087C0   .  6A 01         push    1                 ; /TimerID = 1
010087C2   .  FF35 30980001 push    dword ptr [1009830]    ; |hWnd,在CreateWindowExW后保存窗口句柄的地址
010087C8   .  FF15 34300101 call    dword ptr [<&user32.KillTimer>]  ; \KillTimer,撤销定时器
010087CE   .^ EB A7         jmp     short 01008777  ;跳去函数结束清场
010087D0   >  6A 00         push    0                  ; /lParam = 0
010087D2   .  6A 03         push    3                ; |wParam = 3 ,“保存”菜单的ID号
010087D4   .  68 11010000   push    111              ; |Message = WM_COMMAND
010087D9   .  FF35 30980001 push    dword ptr [1009830]      ; |hWnd ,在CreateWindowExW后保存窗口句柄的地址
010087DF   .  FF15 40120001 call    dword ptr [<&USER32.SendMessageW>; \SendMessageW  ;发送点击菜单“保存”的信号给记事本窗口,实现保存功能。
010087E5   .^ EB 90         jmp     short 01008777    ;跳去函数结束清场

 

DLL劫持技术(Hook) By:kanxue

说明

我是从CoDe_Inject帮助下才了解这个DLL劫持技术(或称HOOK),利用这个制作内存补丁非常的好用。Yonsm在几年前,写了个工具AheadLib,可以很方便地生成各类DLL头文件,见本帖2楼。这种补丁方法,适合制作被ASProtect,Armadillo,Themida等各类强壳保护软件的补丁。



当一个可执行文件运行时,Windows加载器将可执行模块映射到进程的地址空间中,加载器分析可执行模块的输入表,并设法找出任何需要的DLL,并将它们映射到进程的地址空间中。

由于输入表中只包含DLL名而没有它的路径名,因此加载程序必须在磁盘上搜索DLL文件。首先会尝试从当前程序所在的目录加载DLL,如果没找到,则在Windows系统目录查找,最后是在环境变量中列出的各个目录下查找。利用这个特点,先伪造一个系统同名的DLL,提供同样的输出表,每个输出函数转向真正的系统DLL。程序调用系统DLL时会先调用当前目录下伪造的DLL,完成相关功能后,再跳到系统DLL同名函数里执行,如图18.4。这个过程用个形象的词来描述就是系统DLL被劫持(hijack)了。

利用这种方法取得控制权后,可以对主程序进行补丁。此种方法只对除kernel32.dll, ntdll.dll等核心系统库以外的DLL有效,如网络应用程序的ws2_32.dll,游戏程序中的d3d8.dll,还有大部分应用程序都调用的lpk.dll,这些DLL都可被劫持。
利用5.6.2章提供的CrackMeNet.exe来演示一下如何利用劫持技术制作补丁,目标文件用Themida v1.9.2.0加壳保护。

1.补丁地址
去除这个CrackMe网络验证方法参考第5章,将相关补丁代码存放到函数PatchProcess( )里。例如将401496h改成:


代码:
00401496 EB 29 jmp short 004014C1

补丁编程实现就是:

代码:
 
unsigned char p401496[2] = {0xEB, 0x29};
WriteProcessMemory(hProcess,(LPVOID)0x401496, p401496, 2, NULL);

p401496这个数组的数据格式,可以用OllyDBG插件获得,或十六进制工具转换。例如Hex Workshop打开文件,执行菜单Edit/Copy As/Source即可得到相应的代码格式。

2.构建输出函数
查看实例CrackMeNet.exe输入表,会发现名称为ws2_32.dll的DLL,因此构造一个同名的DLL来完成补丁任务。伪造的ws2_32.dll有着真实ws2_32.dll一样的输出函数,完整源码见光盘。实现时,可以利用DLL模块中的函数转发器来实现这个目标,其会将对一个函数的调用转至另一个DLL中的另一个函数。可以这样使用一个pragma指令:

代码:
#pragma comment(linker, "/EXPORT:SomeFunc=DllWork.someOtherFunc")

这个pragma告诉链接程序,被编译的DLL应该输出一个名叫SomeFunc的函数。但是SomeFunc函数的实现实际上位于另一个名叫SomeOtherFunc的函数中,该函数包含在称为DllWork. dll的模块中。
如要达到劫持DLL的目的,生成的DLl输出函数必须与目标DLL输出函数名一样,本例可以这样构造pragma指令:

代码:
#pragma comment(linker, "/EXPORT:WSAStartup=_MemCode_WSAStartup,@115")

编译后的DLL,会有与ws2_32.dll同名的一个输出函数WSAStartup,实际操作时,必须为想要转发的每个函数创建一个单独的pragma代码行,读者可以写一个工具或用其他办法,将ws2_32.dll输出函数转换成相应的pragma指令。

当应用程序调用伪装ws2_32.dll的输出函数时,必须将其转到系统ws2_32.dl中去,这部分的代码自己实现。例如WSAStartup输出函数如下构造:

代码:
 
ALCDECL MemCode_WSAStartup(void)
{
GetAddress("WSAStartup");
__asm JMP EAX;//转到系统ws2_32.dll的WSAStartup输出函数
}

其中GetAddress()函数的代码如下:

代码:
 
// MemCode 命名空间
namespace MemCode
{
HMODULE m_hModule = NULL; //原始模块句柄
DWORD m_dwReturn[500] = {0}; //原始函数返回地址
// 加载原始模块
inline BOOL WINAPI Load()
{
TCHAR tzPath[MAX_PATH]={0};
TCHAR tzTemp[MAX_PATH]={0};
GetSystemDirectory(tzPath, sizeof(tzPath));
strcat(tzPath,"\\ws2_32.dll");m_hModule = LoadLibrary(tzPath);//加载系统系统目录下ws2_32.dllif (m_hModule == NULL){wsprintf(tzTemp, TEXT("无法加载 %s,程序无法正常运行。"), tzPath);MessageBox(NULL, tzTemp, TEXT("MemCode"), MB_ICONSTOP);}return (m_hModule != NULL); } // 释放原始模块inline VOID WINAPI Free(){if (m_hModule)FreeLibrary(m_hModule);}// 获取原始函数地址FARPROC WINAPI GetAddress(PCSTR pszProcName){FARPROC fpAddress;TCHAR szProcName[16]={0};TCHAR tzTemp[MAX_PATH]={0}; if (m_hModule == NULL){if (Load() == FALSE)ExitProcess(-1);} fpAddress = GetProcAddress(m_hModule, pszProcName);if (fpAddress == NULL){if (HIWORD(pszProcName) == 0){wsprintf(szProcName, "%d", pszProcName);pszProcName = szProcName;}wsprintf(tzTemp, TEXT("无法找到函数 %hs,程序无法正常运行。"), pszProcName);MessageBox(NULL, tzTemp, TEXT("MemCode"), MB_ICONSTOP);ExitProcess(-2);}return fpAddress;}}using namespace MemCode;

编译后,用LordPE查看伪造的ws2_32.dll输出函数,和真实ws2_32.dll完全一样,如图18.5所示。

查看伪造的ws2_32.dll中任意一个输出函数,例如WSACleanup:


代码:
 
.text:10001CC0 ; int __stdcall WSACleanup()
.text:10001CC0 WSACleanup proc near
.text:10001CC0 push offset aWsacleanup ;"WSACleanup"
.text:10001CC5 call sub_10001000 ;GetAddress(WSACleanup)
.text:10001CCA jmp eax
.text:10001CCA WSACleanup endp

会发现输出函数WSACleanup()首先调用GetAddress(WSACleanup),获得真实ws2_32.dll中WSACleanup的地址,然后跳过去执行,也就是说ws2_32.dll各输出函数被HOOK了。

3.劫持输出函数
ws2_32.dll有许多输出函数,经分析,程序发包或接包时,WSAStartup输出函数调用的比较早,因此在这个输出函数放上补丁的代码。代码如下:

代码:
 
ALCDECL MemCode_WSAStartup(void)
{
hijack();
GetAddress("WSAStartup");
__asm JMP EAX; 
}
hijack()函数主要是判断是不是目标程序,如是就调用PatchProcess()进行补丁。
void hijack()
{
if (isTarget(GetCurrentProcess())) //判断主程序是不是目标程序,是则补丁之
{
PatchProcess(GetCurrentProcess());
}
}

伪造的ws2_32.dll制作好后,放到程序当前目录下,这样当原程序调用WSASTartup函数时就调用了伪造的ws2_32.dll的WSASTartup函数,此时hijack()函数负责核对目标程序校验,并将相关数据补丁好,处理完毕后,转到系统目录下的ws2_32.dll执行。
这种补丁技术,对加壳保护的软件很有效,选择挂接的函数最好是在壳中没有被调用,当挂接函数被执行时,相关的代码己被解压,可以直接补丁了。有些情况下,必须用计数器统计挂接的函数的调用次数来接近OEP。此方法巧妙地绕过了壳的复杂检测,很适合加壳程序的补丁制作。
一些木马或病毒也会利用DLL劫持技术搞破坏,因此当在应用程序目录下发现系统一些DLL文件存在时,应引起注意。

Kanxue
2008.3.8

向大牛致敬   沿着大牛们的足迹前进

VMP脱壳总结

个人在学习脱VMP加壳的过程中总结的一个步骤。按照这个步骤,包括VMP1.6—2.0在内应该有70%-80%能脱壳。脱不了的也别问我,我也刚开始学习。我还想找人问呢。
想要脱VMP的壳,首要工作当然是要找一个强OD啦!至于是什么版本的OD自己多试验几个,网上大把大把的,一般来说只要加载了你想脱的VMP加壳程序不关闭都可以。
其次就是StrongOD.dll这个插件了,现在用的比较多的就是海风月影,同样网上也是大把大把的。下载回来后复制到你的OD程序所在的文件夹里面的plugin里。StrongOD的设置选项搞不懂就全部打钩。
接下来要做的工作就是搞清楚我们要脱壳的程序编程的语言了,可以用PEID或者fastscanner查看,如果在这里看不到也可以在OD载入以后通过里面的字符串判断了。例如VB的程序会出现MSVB—-/VC的会出现MSVC—等等。这些都是程序运行所需要的windows链接文件。
做完这些预备工作接下来当然是用OD载入文件啦。文件载入后在反汇编窗口CTRL+G搜索VirtualProtect(注意V跟P要大写,至于为什么要搜索这个别问我)。一般来说搜索的结果会出现以下的类似:
7C801AE3    E8 75FFFFFF     call kernel32.VirtualProtectEx
我们在这里下F2断点。然后F9运行到我们下的这个断点。接下来我们就要注意观察堆栈窗口了。一般来说当我们F9运行到我们上面下的断点的时候在堆栈窗口会出现以下类似:
0012F66C   00401000  |Address = TradeCen.00401000
0012F670   000280D1  |Size = 280D1 (164049.)
0012F674   00000004  |NewProtect = PAGE_READWRITE
0012F678   0012FF98  \pOldProtect = 0012FF98
我们要注意观察的就是在接下来我们F9运行的时候,ADDRESS和NEWPROTECT这两行的变化。按F9-速度别太快,直到NewProtect项变为PAGE_READONLY,这时候程序就释放完毕了。
0012F66C   0042A000  |Address = TradeCen.0042A000
0012F670   000069DE  |Size = 69DE (27102.)
0012F674   00000002  |NewProtect = PAGE_READONLY
0012F678   0012FF98  \pOldProtect = 0012FF98
现在可以取消刚才我们下的断点了。接下来就是找OEP了。找OEP的时候我个人的一个经验就是OEP一般就在接近上面的ADDRESS地址的附近。例如上面的地址是0042A000,我一般就在这个基础上减到420000搜索程序的特征段,当然我们也可以直接跳到401000开始搜索。虽然我们搜索的范围比较大,但是因为我们搜索的是命令序列,所以工作量还不是很大。
废话不多说,CTRL+G–上面的地址,然后CTRL+S 查找命令序列。命令序列的内容就是我们用查到的编程语言的特征段。我们可以在特征段里面选择两三句固定不变的命令查找。例如VC++6.0的特征段是
0046C07B U>  55                push ebp
0046C07C     8BEC              mov ebp,esp
0046C07E     6A FF             push -1
0046C080     68 18064C00       push UltraSna.004C0618
0046C085     68 F8364700       push UltraSna.004736F8
0046C08A     64:A1 00000000    mov eax,dword ptr fs:[0]
0046C090     50                push eax
0046C091     64:8925 00000000  mov dword ptr fs:[0],esp
0046C098     83EC 58           sub esp,58
0046C09B     53                push ebx
0046C09C     56                push esi
0046C09D     57                push edi
我们可以只搜索前三条命令。找到符合前三条命令的,我们在对照接下来的命令。只要命令相符那这个地址八九不离十就是OEP了。如果在ADDRESS地址附近找不到OEP,那就只好用笨办法,从401000开始找吧。
找到OEP地址后,我们在OEP处点鼠标右键《此处为新EIP》。接下来就可以dump啦。通常选择OD的dump插件脱壳要好点,用loadpe脱壳后要么程序不运行要么干脆没脱。用OD的dump插件脱壳的时候,脱壳窗口下面的(重建输入表)项前面的勾一定要去掉,这个也是前辈总结的经验。
到此脱壳就结束了。可以试验一下脱壳后的程序了。能运行说明它在70-80%的范围,不能运行的话那也是我还在学习的内容,大家共同探讨!
以下是主要几种编程语言的OEP特征段:
Borland C++
0040163C B> /EB 10             jmp short Borland_.0040164E
0040163E    |66:623A           bound di,dword ptr ds:[edx]
00401641    |43                inc ebx
00401642    |2B2B              sub ebp,dword ptr ds:[ebx]
00401644    |48                dec eax
00401645    |4F                dec edi
00401646    |4F                dec edi
00401647    |4B                dec ebx
00401648    |90                nop
00401649   -|E9 98E04E00       jmp SHELL32.008EF6E6
0040164E    \A1 8BE04E00       mov eax,dword ptr ds:[4EE08B]
00401653     C1E0 02           shl eax,2
00401656     A3 8FE04E00       mov dword ptr ds:[4EE08F],eax
0040165B     52                push edx
0040165C     6A 00             push 0
0040165E     E8 DFBC0E00       call <jmp.&KERNEL32.GetModuleHandleA>
**********************************************************************************
Delphi
00458650 D>  55                push ebp
00458651     8BEC              mov ebp,esp
00458653     83C4 F0           add esp,-10
00458656     B8 70844500       mov eax,Delphi.00458470
0045865B     E8 00D6FAFF       call Delphi.00405C60
00458660     A1 58A14500       mov eax,dword ptr ds:[45A158]
00458665     8B00              mov eax,dword ptr ds:[eax]
00458667     E8 E0E1FFFF       call Delphi.0045684C
0045866C     A1 58A14500       mov eax,dword ptr ds:[45A158]
00458671     8B00              mov eax,dword ptr ds:[eax]
00458673     BA B0864500       mov edx,Delphi.004586B0
00458678     E8 DFDDFFFF       call Delphi.0045645C
0045867D     8B0D 48A24500     mov ecx,dword ptr ds:[45A248]            ; Delphi.0045BC00
00458683     A1 58A14500       mov eax,dword ptr ds:[45A158]
00458688     8B00              mov eax,dword ptr ds:[eax]
0045868A     8B15 EC7D4500     mov edx,dword ptr ds:[457DEC]            ; Delphi.00457E38
00458690     E8 CFE1FFFF       call Delphi.00456864
00458695     A1 58A14500       mov eax,dword ptr ds:[45A158]
0045869A     8B00              mov eax,dword ptr ds:[eax]
0045869C     E8 43E2FFFF       call Delphi.004568E4
**********************************************************************************
Visual C++ 6.0
0046C07B U>  55                push ebp
0046C07C     8BEC              mov ebp,esp
0046C07E     6A FF             push -1
0046C080     68 18064C00       push UltraSna.004C0618
0046C085     68 F8364700       push UltraSna.004736F8
0046C08A     64:A1 00000000    mov eax,dword ptr fs:[0]
0046C090     50                push eax
0046C091     64:8925 00000000  mov dword ptr fs:[0],esp
0046C098     83EC 58           sub esp,58
0046C09B     53                push ebx
0046C09C     56                push esi
0046C09D     57                push edi
0046C09E     8965 E8           mov dword ptr ss:[ebp-18],esp
0046C0A1     FF15 74824A00     call dword ptr ds:[<&KERNEL32.GetVersion>]  ; kernel32.GetVersion
0046C0A7     33D2              xor edx,edx
0046C0A9     8AD4              mov dl,ah
0046C0AB     8915 403F4F00     mov dword ptr ds:[4F3F40],edx
0046C0B1     8BC8              mov ecx,eax
0046C0B3     81E1 FF000000     and ecx,0FF
0046C0B9     890D 3C3F4F00     mov dword ptr ds:[4F3F3C],ecx
**********************************************************************************
Visual C++ 7.0
0100739D > $  6A 70         push 0x70
0100739F   .  68 98180001   push NOTEPAD.01001898
010073A4   .  E8 BF010000   call NOTEPAD.01007568
010073A9   .  33DB          xor ebx,ebx
**********************************************************************************
汇编
00401000 汇>  6A 00            push 0
00401002     E8 C50A0000       call <jmp.&KERNEL32.GetModuleHandleA>
00401007     A3 0C354000       mov dword ptr ds:[40350C],eax
0040100C     E8 B50A0000       call <jmp.&KERNEL32.GetCommandLineA>
00401011     A3 10354000       mov dword ptr ds:[403510],eax
00401016     6A 0A             push 0A
00401018     FF35 10354000     push dword ptr ds:[403510]
0040101E     6A 00             push 0
00401020     FF35 0C354000     push dword ptr ds:[40350C]
00401026     E8 06000000       call 汇编.00401031
0040102B     50                push eax
0040102C     E8 8F0A0000       call <jmp.&KERNEL32.ExitProcess>
00401031     55                push ebp
00401032     8BEC              mov ebp,esp
00401034     83C4 B0           add esp,-50
00401037     C745 D0 30000000  mov dword ptr ss:[ebp-30],30
0040103E     C745 D4 0B000000  mov dword ptr ss:[ebp-2C],0B
00401045     C745 D8 37114000  mov dword ptr ss:[ebp-28],汇编.00401137
**********************************************************************************
VB
0040116C V>/$  68 147C4000     push VB.00407C14
00401171   |.  E8 F0FFFFFF     call <jmp.&MSVBVM60.#100>
00401176   |.  0000            add byte ptr ds:[eax],al
00401178   |.  0000            add byte ptr ds:[eax],al
0040117A   |.  0000            add byte ptr ds:[eax],al
0040117C   |.  3000            xor byte ptr ds:[eax],al

ximo大虾和谐VMP2.05

VMP的外壳部分不能说难,只能说烦。特别是IAT的修复,由于函数调用的错位(并非是规则的call xxxx nop或者nop call xxxx系列)、寄存器使用的随机性、大量的乱序等,使得写脚本修复是个非常蛋疼的事情,而且往往会修复错,修复漏,而VM代码里的IAT更是无法得到修复。于是,目前公开的方法中,最简单的也是最治本的修复方式,就是先生成张调用关系的表,然后写个DLL去读,在程序运行前,修正一些值,来达到跨平台。其他的,还真想不到有更完美的方法。或许牛人间有更好的处理方法,我这种菜鸟实在想不到了。。

至于修复IAT,牛人的文章不少了,比如kissy牛的2个视频,以及aa1ss2牛的学习笔记,这里就不再多说了。

下面写下个人脱壳的记录,当算是个简单的笔记,跟步骤的总结,没什么技术含量,一切都是按牛人的脚步学习的。

试练品是个XP记事本,加上VMP外壳的全选项,顺便把OEP处的代码也给和谐掉。下面开始脱壳:

1.CTRL+G,VirtualProtect,在VirtualProtectEx的调用处下好断点:

7C801AE3    E8 75FFFFFF          call kernel32.VirtualProtectEx

接着,在数据窗口定位到代码段,比如,这个样本的为01001000.主要是为了观察是否已经解码,找返回的时机。

2.一直F9,一直到代码段解码,取消断点。ALT+F9,返回到程序代码区。

3.HOOK VM_RETN,找程序的入口。

先来看下VM_RETN这条handler长成啥样吧:

01071753 Main     pushad                                  //VM_Retn
01071754 Main     xchg ax,di                                ; EAX=0000F694, EDI=0006000E
01071756 Main     jmp NOTEPAD_.0106FB88
0106FB88 Main     sub ch,bl                                 ; ECX=01072F53
0106FB8A Main     mov esp,ebp
0106FB8C Main     movzx cx,al                               ; ECX=01070094
0106FB90 Main     xadd cl,ah                                ; EAX=00009494, ECX=0107008A
0106FB93 Main     call NOTEPAD_.0107152C
0107152C Main     mov ecx,dword ptr ss:[esp+4]              ; ECX=00000246
01071530 Main     xchg eax,esi                              ; EAX=01018E26, ESI=00009494
01071531 Main     mov eax,dword ptr ss:[esp+8]              ; EAX=0006FFB0
01071535 Main     jmp NOTEPAD_.0107147E
0107147E Main     bswap cx                                  ; ECX=00000000
01071481 Main     aaa                                       ; EAX=0006FF00
01071482 Main     mov eax,dword ptr ss:[esp+C]              ; EAX=F035F4BE
01071486 Main     pushfd
01071487 Main     adc esi,A8EF9681                          ; ESI=A8F02B15
0107148D Main     jmp NOTEPAD_.0107163C
0107163C Main     std
0107163D Main     mov esi,dword ptr ss:[esp+14]             ; ESI=0100CB51
01071641 Main     xor di,dx                                 ; EDI=00060248
01071644 Main     neg di                                    ; EDI=0006FDB8
01071647 Main     shld si,sp,cl
0107164B Main     btr bp,0E                                 ; EBP=0006BF84
01071650 Main     mov edi,dword ptr ss:[esp+18]             ; EDI=524DB0B9
01071654 Main     sub esi,734AB4D1                          ; ESI=8DB61680
0107165A Main     lea ebp,dword ptr ds:[edi+DB6A88FF]       ; EBP=2DB839B8
01071660 Main     mov esi,dword ptr ss:[esp+1C]             ; ESI=80A871EF
01071664 Main     inc bp                                    ; EBP=2DB839B9
01071667 Main     rcr bp,cl
0107166A Main     mov ebp,dword ptr ss:[esp+20]             ; EBP=E137F11A
0107166E Main     cmp bl,bh
01071670 Main     movzx bx,dl                               ; EBX=C71A0046
01071674 Main     mov cl,byte ptr ss:[esp+4]                ; ECX=00000098
01071678 Main     bt bx,0F
0107167D Main     mov ebx,dword ptr ss:[esp+24]             ; EBX=05B50161
01071681 Main     rol dh,cl
01071683 Main     mov ecx,dword ptr ss:[esp+28]             ; ECX=213EBC0B
01071687 Main     dec dx                                    ; EDX=00000245
0107168A Main     mov edx,dword ptr ss:[esp+2C]             ; EDX=DA74A7B8
0107168E Main     clc
0107168F Main     add esp,30
01071692 Main     je NOTEPAD_.0106FD6C
01071698 Main     popfd
01071699 Main     pushad
0107169A Main     mov dword ptr ss:[esp],AD22F63E
010716A1 Main     push dword ptr ss:[esp]
010716A4 Main     pushfd
010716A5 Main     push dword ptr ss:[esp+28]
010716A9 Main     retn 2C

直接在010716A9下好断点,F9运行,断下后取消断点,F7,来到下面的地方:

0102A32B    9C                   pushfd
0102A32C    9C                   pushfd
0102A32D    8F0424               pop dword ptr ss:[esp]
0102A330    F5                   cmc
0102A331    81F5 EA0E31E1        xor ebp,E1310EEA
0102A337 ^ E9 29E3FEFF          jmp NOTEPAD_.01018665
0102A33C    AF                   scas dword ptr es:[edi]

4.继续F7几次,就可以来到下面的地方:

01007568    68 BA750001          push NOTEPAD_.010075BA
0100756D    64:A1 00000000       mov eax,dword ptr fs:[0]
01007573    50                   push eax
01007574    8B4424 10            mov eax,dword ptr ss:[esp+10]
01007578    896C24 10            mov dword ptr ss:[esp+10],ebp
0100757C    8D6C24 10            lea ebp,dword ptr ss:[esp+10]
01007580    2BE0                 sub esp,eax
01007582    53                   push ebx
01007583    56                   push esi
01007584    57                   push edi
01007585    8B45 F8              mov eax,dword ptr ss:[ebp-8]
01007588    8965 E8              mov dword ptr ss:[ebp-18],esp
0100758B    50                   push eax
0100758C    8B45 FC              mov eax,dword ptr ss:[ebp-4]
0100758F    C745 FC FFFFFFFF     mov dword ptr ss:[ebp-4],-1
01007596    8945 F8              mov dword ptr ss:[ebp-8],eax
01007599    8D45 F0              lea eax,dword ptr ss:[ebp-10]
0100759C    64:A3 00000000       mov dword ptr fs:[0],eax
010075A2    C3                   retn

这是多么熟悉的代码啊。因为VM并不支持CALL的嵌套,这就给我们可趁之机。先dump一份。

5.下面就来补代码:

此时看堆栈窗口:

0006FFB8   0101654F 返回到 NOTEPAD_.0101654F 来自 NOTEPAD_.0101BFA7 //CALL的出口,注意
0006FFBC   01001898 NOTEPAD_.01001898
0006FFC0   00000070

于是,在代码段,随便找个地址,补入如下代码:

01008890 > 6A 70                push 70
01008892    68 98180001          push dumped1.01001898
01008897    68 4F650101          push dumped1.0101654F
0100889C ^ E9 C7ECFFFF          jmp dumped1.01007568
010088A1    90                   nop

补完后,保存一下,顺便把OEP设置成8890.

OK,程序能够正常。不过此时还不能跨平台。

6.下面开始修复跨平台,这部分我就不说了,自己看牛人的文章跟视频,跑份IAT调用的对应关系表,部分如下:

1013360,DE02099D,comdlg32,PageSetupDlgW
102B3D6,E53997CF,comdlg32,ChooseFontW
1014ABD,4443359,comdlg32,PrintDlgExW
103107A,F8A5F191,comdlg32,ReplaceTextW
1019B4F,8F70D755,comdlg32,GetFileTitleW
101403B,AB122473,comdlg32,FindTextW
101CF16,7495EB47,comdlg32,CommDlgExtendedError
1016371,D8A0FB6B,comdlg32,GetOpenFileNameW
1014D62,BED81FBF,shell32,DragAcceptFiles
10230B9,A0524363,shell32,DragFinish
1022832,F10CB8C9,shell32,DragQueryFileW
101D8F2,4AD7BE0D,comdlg32,GetSaveFileNameW
10314C3,F6D99DC5,shell32,ShellAboutW
102A015,5B0DDC5B,winspool,GetPrinterDriverW
1023366,181A1537,winspool,OpenPrinterW

7.下面就简单的写个DLL,来完成工作,原理很简单,比如某个函数调用中,关键代码如下:

01031019    BA A2390001          mov edx,dump.010039A2
010328AE    8B92 FD430000        mov edx,dword ptr ds:[edx+43FD] //注意这里
010328BE    8D92 DB73ECD6        lea edx,dword ptr ds:[edx+D6EC73DB] //这句出真实的地址

ds:[01007D9F]=A594FBB8
edx=010039A2 (dump.010039A2)

找下对应的关系表:

1007D9F,D6EC73DB,kernel32,GetCommandLineW

可知,在地址01007D9F中存着解密的key,而解密的key为多少,即为真实的API地址-表中对用的key

其实也就是这句的逆过程:lea edx,dword ptr ds:[edx+D6EC73DB]

由于不同的平台,API的地址有差异,所有想要跨平台,就需要修正这个解密的key值,方法是在当前的用户平台上,先获取当前用户平台的API地址,再减去表中对应的那个KEY值即可。

知道了原理,就可以写代码了,代码写的很挫,仅供参考:

#include <windows.h>
#include <stdio.h>

extern “C” BOOL __declspec(dllexport) FkVMPIAT();

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call,LPVOID lpReserved)
{
if (ul_reason_for_call==DLL_PROCESS_ATTACH)
{
FkVMPIAT();
}
return TRUE;
}

BOOL FkVMPIAT()
{
DWORD dwImageBase=(DWORD)GetModuleHandle(NULL);
PIMAGE_DOS_HEADER pDosHeader=(PIMAGE_DOS_HEADER)dwImageBase;
if (pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
{
return FALSE;
}
PIMAGE_NT_HEADERS pNtHeader=(PIMAGE_NT_HEADERS)(dwImageBase+pDosHeader->e_lfanew);
if (pNtHeader->Signature!=IMAGE_NT_SIGNATURE)
{
return FALSE;
}
UINT NumOfSection=pNtHeader->FileHeader.NumberOfSections;
PIMAGE_SECTION_HEADER pSectionHeader=(PIMAGE_SECTION_HEADER)((UINT_PTR)pNtHeader+0x18+
(UINT_PTR)(pNtHeader->FileHeader.SizeOfOptionalHeader));
for(int i=0;i<NumOfSection;i++)
{
DWORD dwSecVA=pSectionHeader->VirtualAddress+dwImageBase;
DWORD dwSecSize=pSectionHeader->Misc.VirtualSize;
DWORD dwOldProtect;
VirtualProtect((LPVOID)dwSecVA,dwSecSize,PAGE_EXECUTE_READWRITE,&dwOldProtect);
pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pSectionHeader+sizeof(IMAGE_SECTION_HEADER));
}
FILE *fp;
fp=fopen(“FkIAT.txt”,”r”);
if (fp==NULL)
{
MessageBox(NULL,”请把fkiat.txt放当前目录下!”,”ximo”,MB_OK|MB_ICONINFORMATION);
}
char buf[256]={0};
while(!feof(fp))
{
fgets(buf,256,fp);
DWORD dwIATAddr,dwKey;
char szIATAddr[10]={0};
char szKey[10]={0};
char szDllName[50]={0};
char szFunName[100]={0};
char *p;
int i=0;
if ((p=strchr(buf,’,’))==NULL)
{
continue;
}
while(buf[i]!=’,’)
{
szIATAddr[i]=buf[i];
i++;
}
sscanf(szIATAddr,”%08x”,&dwIATAddr);
p=strchr(buf,’,’);
i=0;
while(p[i+1]!=’,’)
{
szKey[i]=p[i+1];
i++;
}
sscanf(szKey,”%08x”,&dwKey);

p=strchr(p+1,’,’);
i=0;
while(p[i+1]!=’,’)
{
szDllName[i]=p[i+1];
i++;
}
p=strchr(p+1,’,’);
i=0;
while(p[i+1]!=0x0A)
{
szFunName[i]=p[i+1];
i++;
}
//特殊处理下,不知道是否还有其他动态库也是如此的,想不出好的,只能硬编码了,汗

if (strcmp(szDllName,”winspool”)==0)
{
wsprintf(szDllName,”%s”,”winspool.drv”);
}
//特殊处理2
/*
if ((p=strchr(szDllName,0x20))!=0)
{
wsprintf(szDllName,”%s”,p+1);
}*/
if ((p=strstr(szDllName,”offset”))!=0)
{
wsprintf(szDllName,”%s”,p+7);
}
HMODULE hdll=GetModuleHandle(szDllName);
if (!hdll)
{
hdll=LoadLibrary(szDllName);
}
DWORD dwIAT=(DWORD)GetProcAddress(hdll,(LPCSTR)szFunName);
DWORD dwWrite=dwIAT-dwKey;
__asm
{
pushad
mov eax,dwIATAddr
mov ecx,dwWrite
mov dword ptr [eax],ecx
popad
}
}
fclose(fp);

return TRUE;
}

8,最后就是用PE工具把这个DLL加到脱壳后文件的导入表中了。这个用LORDPE,CFF等工具都能搞定了。

然后把3个文件:脱壳后文件,DLL,以及对应关系的txt这3个文件放在一起,就OK了。放到其他平台测试一下,OK了。

脱壳也就到此结束了。

附上试练品,脱壳后的文件,DLL等吧。

http://u.115.com/file/t063e0b7a9

 

DNF如意0410A版破解小记

               首先OD载入,F9运行之(可能有时候要开DNF才能开外挂)  在VIP用户QQ处输入测试号123456 点击登入,弹出“登录失败,您不是会员,请充值!”  回到OD界面暂停   点击上面的“K”  查看调用堆栈    找到

 调用堆栈:     主线程, 条目 8

地址=0012E05C
堆栈=03630F8A
函数过程=? USER32.MessageBoxExA
调用来自=03630F85
结构=0012E058

在其上Ctrl+F9执行到返回

   然后点击被暂停的错误窗口 回到OD  F8跟进  知道程序跑到0040100后面

查找ASCII码

找到第一次提示登陆成功的地方

 

 

00404133   /0F84 29010000   je DnF如意0.00404262
00404139    6A 00           push 0x0
0040413B    6A 00           push 0x0
0040413D    6A 00           push 0x0
0040413F    68 01030080     push 0x80000301
00404144    6A 00           push 0x0
00404146    68 00000000     push 0x0
0040414B    68 04000080     push 0x80000004
00404150    6A 00           push 0x0
00404152    68 E1695400     push DnF如意0.005469E1      ; 登陆成功,进入仓库等30秒按HOME键呼出挂,如果呼不出请先开游戏后再开挂
00404157    68 03000000     push 0x3
0040415C    BB 30574100     mov ebx,DnF如意0.00415730
 
记住00404139这个地址(不能再上去了,跳转太多顾不上)
 
然后继续查找ASCII码
 
找到提示“用户过期,请充值”(应该有两处)
第一处
0040E8FC    68 00000000     push 0x0
0040E901    68 04000080     push 0x80000004
0040E906    6A 00           push 0x0
0040E908    68 E9BE6500     push DnF如意0.0065BEE9                     ; 用户已过期,请充值!
0040E90D    68 03000000     push 0x3
0040E912    BB 30574100     mov ebx,DnF如意0.00415730
0040E917    E8 A94A0000     call DnF如意0.004133C5
0040E91C    83C4 28         add esp,0x28
0040E91F    E9 2B050000     jmp DnF如意0.0040EE4F
 
第二处
 
0040EDC5    6A 00           push 0x0
0040EDC7    68 00000000     push 0x0
0040EDCC    68 04000080     push 0x80000004
0040EDD1    6A 00           push 0x0
0040EDD3    68 E9BE6500     push DnF如意0.0065BEE9                     ; 用户已过期,请充值!
0040EDD8    68 03000000     push 0x3
0040EDDD    BB 30574100     mov ebx,DnF如意0.00415730
0040EDE2    E8 DE450000     call DnF如意0.004133C5
0040EDE7    83C4 28         add esp,0x28
0040EDEA    E9 30000000     jmp DnF如意0.0040EE1F
0040EDEF    6A 00           push 0x0
 
将这两处call后面的地址均改成00404139
 
别以为大功告成了  这要是以前确实可以了  但我们还稍微下拉一点就会发现还有两处提示
 
0040EDFC    68 00000000     push 0x0
0040EE01    68 04000080     push 0x80000004
0040EE06    6A 00           push 0x0
0040EE08    68 FEBE6500     push DnF如意0.0065BEFE                     ; 登陆失败!登陆失败!您不会会员请充值
0040EE0D    68 03000000     push 0x3
0040EE12    BB 30574100     mov ebx,DnF如意0.00415730
0040EE17    E8 A9450000     call DnF如意0.004133C5
0040EE1C    83C4 28         add esp,0x28
0040EE1F    6A 00           push 0x0
0040EE21    6A 00           push 0x0
0040EE23    6A 00           push 0x0
0040EE25    68 01030080     push 0x80000301
0040EE2A    6A 00           push 0x0
0040EE2C    68 00000000     push 0x0
0040EE31    68 04000080     push 0x80000004
0040EE36    6A 00           push 0x0
0040EE38    68 FEBE6500     push DnF如意0.0065BEFE                     ; 登陆失败!登陆失败!您不会会员请充值
0040EE3D    68 03000000     push 0x3
0040EE42    BB 30574100     mov ebx,DnF如意0.00415730
0040EE47    E8 79450000     call DnF如意0.004133C5
0040EE4C    83C4 28         add esp,0x28
0040EE4F    8B5D FC         mov ebx,dword ptr ss:[ebp-0x4]
0040EE52    85DB            test ebx,ebx
 
我们得把这两处的Call也得Call到正确的地方去  即00404139
 
这才算大功告成,由于DNF如意一直加的TMD壳   真TMD难搞  非我等菜鸟所能脱的  那么就做内存补丁吧
地址都找到了  内存补丁也容易了  附我的内存补丁
 
下面附上两张破解成功的图
 

OD脚本入门

用一个最最简单的ASPack壳为例子,来进行讲解!

我们先来脱一下这个壳吧:

方法一:

00430001 >60pushad //入口点,F8
00430002E8 03000000 call QQ个性网.0043000A //到这后,用ESP定律,下硬件

访问断点
00430007- E9 EB045D45 jmp 45A004F7
0043000C55push ebp
0043000DC3retn
0043000EE8 01000000 call QQ个性网.00430014
00430013EB 5D jmp short QQ个性网.00430072
00430015BB EDFFFFFF mov ebx,-13
0043001A03DDadd ebx,ebp
0043001C81EB 00000300 sub ebx,30000
0043002283BD 22040000 0>cmp dword ptr ss:[ebp+422],0
00430029899D 22040000 mov dword ptr ss:[ebp+422],ebx
0043002F0F85 65030000 jnz QQ个性网.0043039A
004300358D85 2E040000 lea eax,dword ptr ss:[ebp+42E]

继续阅读OD脚本入门