编写一个文件补丁

来源:互联网 发布:人工智能将来发展方向 编辑:程序博客网 时间:2024/05/16 14:15

作者 : Detten    Detten@tiscali.be

 

翻译 : nbw       www.vxer.com

 

来源 : http://biw.rult.at/

 

1、前言

    但破解了一个程序,你就想把成果共享给别人。为了不用把整个破解后的程序上传,你可以制作一个小补丁来修改程序中必要的字节。

    那如何来写呢?

===首先找到需要打补丁的文件。大多数补丁认为该文件处在自己当前目录下。

 

===如果找到,打开该文件。

 

===然后检查打开的文件是不是和所破解的文件。比如我们可以检查文件大小,或者随机检查一些字节,或者最好检查将要被修改的字节。

 

===如果以上都无误,我们可以做需要调整:)

    把文件指针移动到指定位置,然后写入新的操作码。

 

===关闭文件,给出提示结果。

 

下面找一个你破解的文件,然后开始....

 

2、必要的API

   做这个程序需要用到什么API呢?

 

HANDLE CreateFile(

 

LPCTSTR lpFileName, // pointer to name of the file

DWORD dwDesiredAccess, // access (read-write) mode

DWORD dwShareMode, // share mode

LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes

DWORD dwCreationDistribution, // how to create

DWORD dwFlagsAndAttributes, // file attributes

HANDLE hTemplateFile // handle to file with attributes to copy

);

 

 

 

 

   这个API函数用来打开或者创建文件。

dwDesiredAccess 应该设置为: 'GENERIC_WRITE OR GENERIC_READ' ,因为需要读写文件;

dwShareMode = 'FILE_SHARE_WRITE OR FILE_SHARE_READ'

dwCreationDistribution = 'OPEN_EXISTING'  我们只需要打开文件,如果文件不存在函数将返回失败,然后我们给出提示信息。

   可以察看WIN32.HLP获取详细信息,如果你没有这个API库,可以找相关资料。

   如你所见,这个API函数返回我们需要文件句柄。我们可以利用这个句柄做下一步:写文件。

 

BOOL WriteFile(

HANDLE hFile, // handle to file to write to

LPCVOID lpBuffer, // pointer to data to write to file

DWORD nNumberOfBytesToWrite, // number of bytes to write

LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written

LPOVERLAPPED lpOverlapped // pointer to structure needed for overlapped I/O

);

 

   我们用这个函数把2个字节写入需要打补丁的文件(当然是在正确的位置)[译者:作者的例子是写2个字节,我们做的时候根据需要]

   涉及到的hFile句柄就是CreateFile函数的返回值。

 

lpOverlapped应该指向一个 OVERLAPPED 结构,我们需要用它设定正确的文件指针。

 

typedef struct _OVERLAPPED { // o

DWORD Internal;

DWORD InternalHigh;

DWORD Offset;

DWORD OffsetHigh;

HANDLE hEvent;

} OVERLAPPED;

Offset的内容是需要写入的地址。(译者:注意不是内存中的虚拟地址)

 

3、目标

   目标程序是Crackme5.exe,假定我们现在获取不到正确的序列号,而需要对他打补丁(译者:这个程序我也没有,大家知道意思就行)

   当然你肯定是不错的Cracker:) 并且很快找出来了需要修补的地方:

 

Offset 53Fh : 74h, 15h -> 90h, 90h

 

   以上就是我们所需要的所有信息。

 

4、代码

 

386

.model flat,stdcall

option casemap:none

include /masm32/include/windows.inc

include /masm32/include/user32.inc

include /masm32/include/kernel32.inc

includelib /masm32/lib/user32.lib

includelib /masm32/lib/kernel32.lib

 

 

.data

FileName db "Crackme5.exe",0

AppName db "Crackme 5 Patch",0

Done db "File patched succesfully !",0

NoFile db "Can't find crackme5.exe !",0

ReFile db "Wrong version of crackme5.exe !",0

WrFile db "Error writing to crackme5.exe !",0

RBuffer db 75h, 15h

WBuffer db 90h,90h

OffsetPos OVERLAPPED <NULL,NULL,53Fh,NULL,NULL>

 

.data?

 

hInstance HINSTANCE ?

CommandLine LPSTR ?

hwndname HWND ?

hFile HANDLE ?

Numb dd ?

Buffer db 2 dup(?)

 

 

.const

 

.code

start:

 

invoke GetModuleHandleA, NULL

mov hInstance,eax

 

invoke CreateFile,ADDR FileName, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL

 

.IF eax!=INVALID_HANDLE_VALUE

 

mov hFile, eax ; 存储文件句柄

Invoke ReadFile, hFile, ADDR Buffer, 2, ADDR Numb, ADDR OffsetPos ; 读取要修改的2个字节

mov ax, word ptr [Buffer]

.IF ax == word ptr [RBuffer] ; 如果判断正确 (75h,15h) 就覆盖他们 :-)

Invoke WriteFile, hFile, ADDR WBuffer, 2, ADDR Numb, ADDR OffsetPos ;写入新的代码(90h 90h)

.IF Numb == 2 ; 如果返回值为 2, 弹出成功信息

push MB_OK

push OFFSET AppName

push OFFSET Done ; 弹出信息地址入

.ELSE ;如果返回值不是2,那么弹出错误信息

push MB_OK OR MB_ICONINFORMATION

push OFFSET AppName

push OFFSET WrFile

.ENDIF

.ELSE ; 如果读取的2个字节不正确,弹出文件选择错误信息

push MB_OK OR MB_ICONINFORMATION

push OFFSET AppName

push OFFSET ReFile

.ENDIF

 

.ELSE ; 如果未获得文件句柄,弹出文件不存在信息

push MB_OK OR MB_ICONINFORMATION

push OFFSET AppName

push OFFSET NoFile

.ENDIF

 

push NULL

Call MessageBox

invoke CloseHandle, hFile ; 关闭文件

invoke ExitProcess,eax ; 退出

 

end start

 

   如果你看懂了上面的代码,就可以制作自己的文件补丁。当然也可以编写的更人性化一些,比如添加上选择文件路径的对话框,但那就是另外一个题目了。

 

 

原文:

 Make a standalone patch

 

1. General Theory

 

Once you patched a program you cracked, you might want to share it. Instead of uploading the entire executable, you can make a small patch that changes the neccessary bytes.

 

Now how are we going to do that?

 

=> First we have to look for the file we have to patch. Most patches suppose that the file is in the same directory.

 

=> If it's there, we have to open it.

 

=> Next we should check if it's the exact same file as the one we cracked. We could eg. check the size, or some random bytes, or even better, the bytes we are going to patch.

 

=> If it is the same, we can do the neccessary adjustments : )

Put the filepointer on the right position, and write the new opcodes to it.

 

=> Close the file, and give a message about the status.

 

 

 

Take a program you just cracked, or use this example I will use.

Let's code this...

 

2. API Theory

 

 

What API's will we need to code this?

 

First of all, we will have to open the executable. The suitable API is :

 

HANDLE CreateFile(

 

LPCTSTR lpFileName, // pointer to name of the file

DWORD dwDesiredAccess, // access (read-write) mode

DWORD dwShareMode, // share mode

LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes

DWORD dwCreationDistribution, // how to create

DWORD dwFlagsAndAttributes, // file attributes

HANDLE hTemplateFile // handle to file with attributes to copy

);

 

This API is used for opening, or creating a file.

dwDesiredAccess should be 'GENERIC_WRITE OR GENERIC_READ' because we want to read and write from/to the file.

dwShareMode = 'FILE_SHARE_WRITE OR FILE_SHARE_READ'

dwCreationDistribution = 'OPEN_EXISTING' We only want to open a file that is there. If it's not there, the function will fail, and we can give an Error Message.

Check your WIN32.HLP for details. If you don't have this API library, get it in the Reference section.

As you can see the API returns the handle of the file we requested. We need this handle for the next step : writing to the file.

 

BOOL WriteFile(

HANDLE hFile, // handle to file to write to

LPCVOID lpBuffer, // pointer to data to write to file

DWORD nNumberOfBytesToWrite, // number of bytes to write

LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written

LPOVERLAPPED lpOverlapped // pointer to structure needed for overlapped I/O

);

 

 

We will use this API to write the two bytes to the file (in the right place, of course :)

The handle hFile is the one CreateFile has returned.

 

lpOverlapped should point to an OVERLAPPED structure. We need this to put the filepointer at the right offset.

 

typedef struct _OVERLAPPED { // o

DWORD Internal;

DWORD InternalHigh;

DWORD Offset;

DWORD OffsetHigh;

HANDLE hEvent;

} OVERLAPPED;

 

Offset will contain the position where we want to write.

 

3. The Target

 

 

The Target is crackme5.exe, let's say we don't find a valid serial, and we want to patch it.

Of course you are a good cracker : ) and you found the bytes to patch quickly.

Here they are :

 

 

 

 

Offset 53Fh : 74h, 15h -> 90h, 90h

 

That's all the information we need : )

 

4. The Code

 

; Find the complete source and binary here.

 

.386

.model flat,stdcall

option casemap:none

include /masm32/include/windows.inc

include /masm32/include/user32.inc

include /masm32/include/kernel32.inc

includelib /masm32/lib/user32.lib

includelib /masm32/lib/kernel32.lib

 

 

.data

FileName db "Crackme5.exe",0

AppName db "Crackme 5 Patch",0

Done db "File patched succesfully !",0

NoFile db "Can't find crackme5.exe !",0

ReFile db "Wrong version of crackme5.exe !",0

WrFile db "Error writing to crackme5.exe !",0

RBuffer db 75h, 15h

WBuffer db 90h,90h

OffsetPos OVERLAPPED <NULL,NULL,53Fh,NULL,NULL>

 

.data?

 

hInstance HINSTANCE ?

CommandLine LPSTR ?

hwndname HWND ?

hFile HANDLE ?

Numb dd ?

Buffer db 2 dup(?)

 

 

.const

 

.code

start:

 

invoke GetModuleHandleA, NULL

mov hInstance,eax

 

invoke CreateFile,ADDR FileName, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL

 

.IF eax!=INVALID_HANDLE_VALUE

 

mov hFile, eax ; Store handle of file

Invoke ReadFile, hFile, ADDR Buffer, 2, ADDR Numb, ADDR OffsetPos ; Read the 2 bytes we are going to patch

mov ax, word ptr [Buffer]

.IF ax == word ptr [RBuffer] ; If they are the right ones (75h,15h) we replace them :-)

Invoke WriteFile, hFile, ADDR WBuffer, 2, ADDR Numb, ADDR OffsetPos ; Write the new bytes (90h 90h)

.IF Numb == 2 ; If the number of bytes written = 2, give Done Message

push MB_OK

push OFFSET AppName

push OFFSET Done ; Push Done-Message

.ELSE ; If number of Bytes != 2, Give Error-writing-Message

push MB_OK OR MB_ICONINFORMATION

push OFFSET AppName

push OFFSET WrFile

.ENDIF

.ELSE ; If the 2 bytes read are not the right ones, Give Error-Version-Message

push MB_OK OR MB_ICONINFORMATION

push OFFSET AppName

push OFFSET ReFile

.ENDIF

 

.ELSE ; If the handle was not returned, Give Error-NoFile-Message

push MB_OK OR MB_ICONINFORMATION

push OFFSET AppName

push OFFSET NoFile

.ENDIF

 

push NULL

Call MessageBox

invoke CloseHandle, hFile ; Close File

invoke ExitProcess,eax ; Exit

 

end start

 

 

If you understand the code above, which is self-explanatory, you can try to make a simular patch for another target.

 

Now you can make a simple WIN32ASM-patch. Of course we can also make a more user-friendly version eg. with an open-dialogbox to select the target. But that will be covered in a next tutorial about the subject : )

 

If you have questions, remarks about this tutorial, mail me!

 

Greetings,

 

Detten

Detten@tiscali.be