本来是没有打算这篇文章的,看到在上篇文章中yumikeyabc兄弟提供了一个直接找Point-h的工具(16楼),下载后试用了一下,发现得到的地址是不对的,以前也用过另一个,同样得到的Point-h地址不对,所以就自己动手写了一个垃圾品,还是老话,大家不要扔臭鸡蛋、烂柿子就好了,抛砖引玉嘛。
原理和上篇里面讲解的一样,从user32.dll文件里面搜索F3 A5 8B C8 83 E1 03 F3 A4 E8数值,用得到的值 + 基址 + 这个值所在区段的虚拟偏移 ? 原始偏移量就可以了,代码很简单。
一个前辈写的Point-h中的关键代码分析,因为得出的结果是错的,所以就反来看看。
00401010 |> \55 push ebp
00401011 |. 8BEC mov ebp,esp ; ebp =0012ff30
00401013 |. 81EC 88000000 sub esp,88
00401019 |. 53 push ebx
0040101A |. 56 push esi
0040101B |. 57 push edi
0040101C |. 8DBD 78FFFFFF lea edi,dword ptr ss:[ebp-88]
00401022 |. B9 22000000 mov ecx,22
00401027 |. B8 CCCCCCCC mov eax,CCCCCCCC
0040102C |. F3:AB rep stos dword ptr es:[edi]
0040102E |. C745 FC 00000>mov dword ptr ss:[ebp-4],0 ; 开辟变量空间
00401035 |. C645 EC 8B mov byte ptr ss:[ebp-14],8B ; 同上,这个值是连续的,应该是个数组
00401039 |. C645 ED C1 mov byte ptr ss:[ebp-13],0C1 ; 可以看到这些连续的数字正是我们要查
0040103D |. C645 EE C1 mov byte ptr ss:[ebp-12],0C1 ; 找的
00401041 |. C645 EF E9 mov byte ptr ss:[ebp-11],0E9 ; 8bc1c1e902f3a58bc883e103f3a4e800
00401045 |. C645 F0 02 mov byte ptr ss:[ebp-10],2 ; 共16Byte
00401049 |. C645 F1 F3 mov byte ptr ss:[ebp-F],0F3
0040104D |. C645 F2 A5 mov byte ptr ss:[ebp-E],0A5
00401051 |. C645 F3 8B mov byte ptr ss:[ebp-D],8B
00401055 |. C645 F4 C8 mov byte ptr ss:[ebp-C],0C8
00401059 |. C645 F5 83 mov byte ptr ss:[ebp-B],83
0040105D |. C645 F6 E1 mov byte ptr ss:[ebp-A],0E1
00401061 |. C645 F7 03 mov byte ptr ss:[ebp-9],3
00401065 |. C645 F8 F3 mov byte ptr ss:[ebp-8],0F3
00401069 |. C645 F9 A4 mov byte ptr ss:[ebp-7],0A4
0040106D |. C645 FA E8 mov byte ptr ss:[ebp-6],0E8
00401071 |. C645 FB 00 mov byte ptr ss:[ebp-5],0
00401075 |. C645 DC 00 mov byte ptr ss:[ebp-24],0 ; 开辟变量空间
00401079 |. 33C0 xor eax,eax
0040107B |. 8945 DD mov dword ptr ss:[ebp-23],eax
0040107E |. 8945 E1 mov dword ptr ss:[ebp-1F],eax
00401081 |. 8945 E5 mov dword ptr ss:[ebp-1B],eax
00401084 |. 66:8945 E9 mov word ptr ss:[ebp-17],ax
00401088 |. 8845 EB mov byte ptr ss:[ebp-15],al ; [24-15]连续开辟了16Byte的空间
0040108B |. 8BF4 mov esi,esp ; esp = 0012ef9c
0040108D |. 68 58004200 push punto_h.00420058 ; /FileName = "user32.dll"
00401092 |. FF15 90514200 call dword ptr ds:[<&KERNEL32.LoadLibrar>; \LoadLibraryA
00401098 |. 3BF4 cmp esi,esp ; esp = 0012fe9c
0040109A |. E8 71010000 call punto_h.00401210 ; 返回user32.dll的基址
0040109F |. 8945 FC mov dword ptr ss:[ebp-4],eax ; eax = 77d10000
004010A2 |. 837D FC 00 cmp dword ptr ss:[ebp-4],0
004010A6 |. 75 1D jnz short punto_h.004010C5 ; 基址<>0不做错误处理
004010A8 |. 8BF4 mov esi,esp
004010AA |. 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
004010AC |. 68 50004200 push punto_h.00420050 ; |Title = "ERROR"
004010B1 |. 68 38004200 push punto_h.00420038 ; |Text = "DLL no encontrada"
004010B6 |. 6A 00 push 0 ; |hOwner = NULL
004010B8 |. FF15 AC524200 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
004010BE |. 3BF4 cmp esi,esp
004010C0 |. E8 4B010000 call punto_h.00401210
004010C5 |> 8B4D FC mov ecx,dword ptr ss:[ebp-4] ; ecx <- 77d10000
004010C8 |. 894D D8 mov dword ptr ss:[ebp-28],ecx ; ebp-28 <- 77d10000
004010CB |. C745 BC 00000>mov dword ptr ss:[ebp-44],0 ; 开辟循环变量空间
004010D2 |. EB 09 jmp short punto_h.004010DD ; 先跳转比较循环变量
004010D4 |> 8B55 BC /mov edx,dword ptr ss:[ebp-44]
004010D7 |. 83C2 01 |add edx,1
004010DA |. 8955 BC |mov dword ptr ss:[ebp-44],edx
004010DD |> 817D BC FFFF0> cmp dword ptr ss:[ebp-44],3FFFF ; 变量与0x3ffff作比较(循环次数)
004010E4 |. 7D 55 |jge short punto_h.0040113B ; 大于等于跳出
004010E6 |. C745 B8 00000>|mov dword ptr ss:[ebp-48],0 ; 开辟循环变量空间
004010ED |. EB 09 |jmp short punto_h.004010F8 ; 先跳转比较循环变量
004010EF |> 8B45 B8 |/mov eax,dword ptr ss:[ebp-48] ; 变量初始值为0
004010F2 |. 83C0 01 ||add eax,1 ; 变量+1
004010F5 |. 8945 B8 ||mov dword ptr ss:[ebp-48],eax
004010F8 |> 837D B8 10 | cmp dword ptr ss:[ebp-48],10 ; 变量与0x10作比较(循环次数)
004010FC |. 7D 15 ||jge short punto_h.00401113 ; 大于等于跳出
004010FE |. 8B4D D8 ||mov ecx,dword ptr ss:[ebp-28] ; ebp-28 = 77d10000
00401101 |. 034D B8 ||add ecx,dword ptr ss:[ebp-48]
00401104 |. 8B55 B8 ||mov edx,dword ptr ss:[ebp-48]
00401107 |. 8B45 BC ||mov eax,dword ptr ss:[ebp-44] ; 偏移量
0040110A |. 8A0C01 ||mov cl,byte ptr ds:[ecx+eax] ; cl <- 基址+偏移量处字符
0040110D |. 884C15 DC ||mov byte ptr ss:[ebp+edx-24],cl ; 12ff30+变量-24
00401111 |.^ EB DC |\jmp short punto_h.004010EF
00401113 |> C645 EB 00 |mov byte ptr ss:[ebp-15],0 ; 4010ef-401111为取16Byte,取完跳到这
00401117 |. 8BF4 |mov esi,esp
00401119 |. 8D55 DC |lea edx,dword ptr ss:[ebp-24] ; 取到的16Byte
0040111C |. 52 |push edx ; /String2
0040111D |. 8D45 EC |lea eax,dword ptr ss:[ebp-14] ; |程序头定义的16Byte
00401120 |. 50 |push eax ; |String1
00401121 |. FF15 8C514200 |call dword ptr ds:[<&KERNEL32.lstrcmpA>>; \lstrcmpA
00401127 |. 3BF4 |cmp esi,esp
00401129 |. E8 E2000000 |call punto_h.00401210
0040112E |. 8945 D4 |mov dword ptr ss:[ebp-2C],eax ; 如果比较2个字符串相等,eax返回0
00401131 |. 837D D4 00 |cmp dword ptr ss:[ebp-2C],0
00401135 |. 75 02 |jnz short punto_h.00401139
00401137 |. EB 02 |jmp short punto_h.0040113B
00401139 |>^ EB 99 \jmp short punto_h.004010D4
0040113B |> 8B4D BC mov ecx,dword ptr ss:[ebp-44] ; ecx <- 找到时的偏移量
0040113E |. 8B55 D8 mov edx,dword ptr ss:[ebp-28] ; user32.dll的基址
00401141 |. 8D440A 05 lea eax,dword ptr ds:[edx+ecx+5] eax = edx+ecx+5 也就是说Point-h还为f3开始的
00401145 |. 8BF4 mov esi,esp
00401147 |. 50 push eax ; /<%x>
00401148 |. 68 34004200 push punto_h.00420034 ; |Format = "%x"
0040114D |. 8D4D C0 lea ecx,dword ptr ss:[ebp-40] ; |
00401150 |. 51 push ecx ; |s
00401151 |. FF15 A8524200 call dword ptr ds:[<&USER32.wsprintfA>] ; \wsprintfA
00401157 |. 83C4 0C add esp,0C
0040115A |. 3BF4 cmp esi,esp
0040115C |. E8 AF000000 call punto_h.00401210
00401161 |. 8BF4 mov esi,esp
00401163 |. 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
00401165 |. 68 1C004200 push punto_h.0042001C ; |Title = "DIRECCION PUNTO H"
0040116A |. 8D55 C0 lea edx,dword ptr ss:[ebp-40] ; |
0040116D |. 52 push edx ; |Text
0040116E |. 6A 00 push 0 ; |hOwner = NULL
00401170 |. FF15 AC524200 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
00401176 |. 3BF4 cmp esi,esp
00401178 |. E8 93000000 call punto_h.00401210
0040117D |. 33C0 xor eax,eax
0040117F |. 5F pop edi
00401180 |. 5E pop esi
程序为C++的,写的很简练,但得出的结果是不对的,偏移量得到的不对,而且00401141处的计算方法也是不对的。
newsearch:
POINT H收集翻译
http://bbs.pediy.com/showthread.php?s=&threadid=10833&highlight=pointh
linhanshi:
Point-h in WinXP english tutorial
http://bbs.pediy.com/showthread.php?s=&threadid=8915&highlight=pointh
最初由 peaceclub 发布 后面的程序读出来的地址还是有问题的,文件offset定位还得考虑到对齐的问题。
按照上面的分析和2篇参考写出具体代码:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
GroupBox1: TGroupBox;
Edit1: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function GetWinDir: string; //得到系统目录
var
Buf: array[0..MAX_PATH] of char;
begin
GetSystemDirectory(Buf, MAX_PATH);
Result := Buf;
if Result[Length(Result)] <> '\' then Result := Result + '\';
end;
function GetFileSize(const FileName: string): LongInt; //取得一个文件的大小
var SearchRec: TSearchRec;
begin
if FindFirst(ExpandFileName(FileName), faAnyFile, SearchRec) = 0 then
Result := SearchRec.Size
else
Result := -1;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
user32Path: string;
tmp: array[1..10] of byte;
i, pPoint: integer;
Stream: TFileStream;
PEDosHead: TImageDosHeader;
PENTHead: TImageNtHeaders;
PESectionHead: array of TImageSectionHeader;
label FoundAnAnswer;
begin
user32Path := GetWinDir + 'user32.dll';
Stream := TFileStream.Create(user32Path, fmShareDenyNone);
Stream.Seek(0, soFromBeginning);
Stream.Read(PEDosHead, sizeof(PEDosHead)); //读PEDosHead结构
Stream.Seek(PEDosHead._lfanew, soFromBeginning); //将指针挪至 $003c
Stream.Read(PENTHead, sizeof(PENTHead)); //读PENTHead结构
SetLength(PESectionHead, PENTHead.FileHeader.NumberOfSections);
for i := 0 to PENTHead.FileHeader.NumberOfSections - 1 do
Stream.Read(PESectionHead[i], SizeOf(PESectionHead[i])); //读PESectionHead结构
//for i := 1 to GetFileSize(user32Path) do
for i := 1 to $3ffff do
begin
Stream.Seek(i,soFromBeginning);
Stream.Read(tmp,sizeof(tmp));
//F3 A5 8B C8 83 E1 03 F3 A4 E8
if (ord(tmp[1])=$F3) and (ord(tmp[2])=$A5) and (ord(tmp[3])=$8B) and
(ord(tmp[4])=$C8) and (ord(tmp[5])=$83) and (ord(tmp[6])=$E1) and
(ord(tmp[7])=$03) and (ord(tmp[8])=$F3) and (ord(tmp[9])=$A4) and
(ord(tmp[10])=$E8) then
begin
pPoint:=i; //记录Offset值
goto FoundAnAnswer;
end;
end;
FoundAnAnswer:
Stream.Free;
//由于万能断点处于.text区段时固定的,所以就直接写PESectionHead[0].SizeOfRawData了
edit1.Text :=IntToHex(PENTHead.OptionalHeader.ImageBase+pPoint+ PESectionHead[0].VirtualAddress - PESectionHead[0].PointerToRawData,8);
end;
end.
<代码已修正,全文完>
上传的附件: