能力值:
( LV2,RANK:10 )
2 楼
用movs 命令吧
不过要先把二个段的地址指定好
能力值:
( LV2,RANK:10 )
3 楼
var
S1:String;
S2:string;
begin
s1:='hello';
asm
mov edi,s1
mov s2,edi
end;
showMessage(s2);
end;
能力值:
( LV2,RANK:10 )
4 楼
ldsjlm所说的方法不灵 你设置了2个string ,我需要的不是把s1的字符串传递到s2的问题 而是把esi所指的字符串传递给 s1 请问应该如何做?
能力值:
( LV2,RANK:10 )
5 楼
var
Temp:DWORD;
s:string;
begin
asm
mov temp,esi
end;
s:=Pchar(temp);
end;
这样呢
能力值:
( LV2,RANK:10 )
6 楼
还是不成 pchar(temp)本身就会造成内存错误 最好是在汇编代码内完成 而且我是修改内存跳到我的代码里的 读完ESI后还要跳回去的
能力值:
( LV12,RANK:450 )
7 楼
procedure TForm1.Button1Click(Sender: TObject);
var
str:String;
s:String;
begin
[COLOR="Teal"] // 从Edit1.Text 中取一个字符串
//我不知到你esi中的字符串是从那里飞来的,所以只能自己凭想象弄一个[/COLOR]
s:=Edit1.Text;
asm
mov esi, s
[COLOR="teal"] // LStrLAsg 的入口参数
// -> EAX pointer to dest
// EDX source[/COLOR]
lea eax, str
mov edx, esi
call system.@LStrLAsg
end;
[COLOR="teal"] // 将 str 里的字符串送到 Edit2中,证明字符串被传递到 str 中了
// 哈哈,是不是太简单了。[/COLOR]
Edit2.Text:=str;
end;
下面再给出一个可能是你想要的方法
procedure TForm1.Button2Click(Sender: TObject);
type
StrRec = packed record
allocSiz: Longint;
refCnt: Longint;
Length: Longint;
end;
const
skew = sizeof(StrRec);
var
str:string;
s:string;
D:Dword;
begin
s:=Edit1.Text;
asm
mov esi, s
[COLOR="teal"] // 使用var 声名的变量 str 只是一个空的指针,在实际使用时必须初始化。
// LStrSetLength 入口参数
// -> EAX Pointer to str
// EDX new length[/COLOR]
lea eax, str
mov edx, [esi-skew].StrRec.Length
push edx
call system.@LStrSetLength
mov edi,str
pop ecx
cld
rep movsb
end;
Edit2.Text:=str;
end;
能力值:
( LV2,RANK:10 )
8 楼
感谢gzgzlxg大哥的回答,不过我不是要把exit1.text的内容传递给str 由于我是HOOK了一段程序的内存 类似打补丁那样 我是要把ESI寄存器执行到这里的字符串传递给str 请问这样应该如何做?
能力值:
( LV12,RANK:450 )
9 楼
就使用第二个方法,关键你需要自己先得到这个在esi中的字符串的长度,然后使用类似上面的方法,你先删除第一句:
mov esi, s //esi已经有你字符串的地址了
然后修改下面这句:
// mov edx, [esi-skew].StrRec.Length
mov edx, esi中字符串的长度
然后就OK了。
再学不会,我也无法教你了,这么简单的修改一下都做不到,前面给出的方法是给你一个思路,程序还是要自己写的,这个思路的关键,就是要知道Delphi内部有一套自己管理字符串的方法,你不能简单的用 rep movsb 这种指令将字符串传递到 Delphi 的字符串中去,必须按照 Delphi 的内部机制去处理,其中第一个方法的前提是,这两个字符串必须是 Delphi 格式的字符串,你那个esi中的字符串显然是不符合这个要求的,所以要使用第二个方法,第一个方法中,Delphi 的那条命令已经自动为目标字符串分配了内存,第二个方法中你就必须自己去为目标字符串分配内存,否则就会发生不可估计的错误。LStrSetLength函数就是为那个字符串分配内存,这样你就可以将esi中的字符串传递到Delphi中了。
能力值:
( LV2,RANK:10 )
10 楼
发过简单的例子,看对你有没有帮助
push 0
push ecx
lea edx, dword ptr [esi+8]
push edx
call 005C3350
add esp, $0C
假入上面的代码是一个加密过程,edx指向需要加密的数据,现在要在加密过程执行之前把数据读出来
下面是一种处理方法:
push 0
push ecx
lea edx, dword ptr [esi+8]
push edx
call GetEnPacket //005C3350 把005C3350替换为GetEnPacket
add esp, 0C
var
SaveDataAddr:DWORD;
temp:DWORD;
funcaddr:DWORD;
procedure ReadData;
var
TempData: DWORD;
Len: DWORD;
str: string;
Mem:PChar;
begin
TempData := SaveDataAddr - 4;
Len := PWORD(TempData)^; //得到数据长度
GetMem(Mem,Len);
CopyMemory(Mem,pointer(TempData),Len);//数据复制到mem
//一些处理
FreeMem(Mem);
end; procedure GetEnPacket;
begin
asm
mov SaveDataAddr,edx //edx指向加密前的数据
end;
asm
pushad
end;
ReadData; //读取数据
asm
popad
end;
asm
pop temp //为了堆栈平衡
mov funcaddr, $005C32F0
CAll funcaddr //call原来的加密过程 .如果果005C32F0
push Temp //为了堆栈平衡
end;
end;
能力值:
( LV2,RANK:10 )
11 楼
收藏啊 学习
能力值:
( LV3,RANK:30 )
12 楼
不知道这个行不行,我也经常要在Delphi中加入汇编,Delphi中有很多类似的函数,有些直接就用汇编写的,我都是自己改的,下面这个是改自Move函数,本来我这个函数里的变量都是局部的,所以对于Source,Str和Count都是用的Mov,如果是全局的话有可能要改成Lea,具体调试下就知道
// LEA ESI,Source {假设此时ESI已经指向了你的源Str,此步忽略}
LEA EDI,str {假设你的Str是全局变量的话}
{如果是局部变量的话应该要Mov Edi,Str,自己试下}
MOV ECX,count {Count为你要复制的长度,全局或局部好像也要处理下}
MOV EAX,ECX
CMP EDI,ESI
JA @@down
JE @@exit
SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit
REP MOVSD
MOV ECX,EAX
AND ECX,03H
REP MOVSB { copy count MOD 4 bytes }
JMP @@exit
@@down:
LEA ESI,[ESI+ECX-4] { point ESI to last dword of source }
LEA EDI,[EDI+ECX-4] { point EDI to last dword of dest }
SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit
STD
REP MOVSD
MOV ECX,EAX
AND ECX,03H { copy count MOD 4 bytes }
ADD ESI,4-1 { point to last byte of rest }
ADD EDI,4-1
REP MOVSB
CLD
@@exit:
能力值:
( LV12,RANK:450 )
13 楼
Sam.com的方法其实就是Delphi Vcl System.pas中 Move 函数的源代码,把这个源代码抄过来不如直接使用这个源代码,在Delphi中对Vcl中的内部函数的调用需要指明该函数所在文件的文件名,这样你就可以直接使用这个 Move 函数了,没有必要将已经现成的东西抄过来使用。
[COLOR="teal"]// ->EAX Pointer to source
// EDX Pointer to destination
// ECX Count[/COLOR]
mov eax,esi
mov edx,str
mov ecx,长度
call system.MOVE
问题的关键还在于没有为字符串分配内存。这样运行结果难以预料。
能力值:
( LV3,RANK:30 )
14 楼
Sam.com的方法其实就是Delphi Vcl System.pas中 Move 函数的源代码,把这个源代码抄过来不如直接使用这个源代码,在Delphi中对Vcl中的内部函数的调用需要指明该函数所在文件的文件名,这样你就可以直接使用这个 Move 函数了,没有必要将已经现成的东西抄过来使用
嗯~~我这个只是把他源代码简单的拿出来用~如果直接Call system.Move的话,不知道会不会把Move这一段编译成如下,我试过在驱动中调用这个函数的话,他是按这个来编译了,驱动执行就死机,但我直接用汇编就没问题了,不知道是什么原因,对于字符串分配内存的问题直接来个Str:=''不就行了吗?:
procedure Move(const Source; var Dest; count : Integer);
{$IFDEF PUREPASCAL}
var
S, D: PChar;
I: Integer;
begin
S := PChar(@Source);
D := PChar(@Dest);
if S = D then Exit;
if Cardinal(D) > Cardinal(S) then
for I := count-1 downto 0 do
D[I] := S[I]
else
for I := 0 to count-1 do
D[I] := S[I];
end;
{$ELSE}
asm
.......
能力值:
( LV12,RANK:450 )
15 楼
不会,如果没有定义纯种的Pascal,就不会发生这样的事。
你可以通过CPU调试窗口,看到这个MOVE的具体代码。
对于字符串分配内存的问题直接来个Str:=''不就行了吗?:
Delphi的字符串管理机制非常复杂,当选择 Huge String 模式,即支持巨型字符串时,对字符串进行操作,只要字符串的长度发生变化,都要重新分配内存来存放新的字符串:
Str:='';
这条指令进行时,Delphi调用的是LStrClr函数,LStrClr函数非常复杂,对于一个已经分配过内存的字符串,LStrClr将释放原来分配的内存,然后重新建立一个空字符串,对于没有初始化过的字符串,LStrClr将分配相应的内存,建立一个没有长度的字符串。
如果没有选择 Huge String 模式,所有字符串都是定长的,这时,Str:='';就直接分配了256字节长度的内存,而且在字符串操作过程中,不会再分配内存。
StrRec = packed record
allocSiz: Longint;
refCnt: Longint;
Length: Longint;
end;
上面的结构是Huge String模式下Delphi的字符串结构,存放在一个字符串的前面,这样做的目的是兼容C格式的字符串,Delphi中的任何字符串指针都是指向这个字符串的起始位置,而不是指向这个字符串的结构位置,这样对一个Delphi的字符串可以直接当作C字符串来操作,但用户进行类似操作的时候,字符串操作的长度不要大于 allocSiz 的长度,这个长度是Delphi在初始化字符串是为该字符串分配的实际空间大小,Length是该字符串的实际长度,allocSiz >= Length。refCnt是一个字符串使用计数器,如果这个计数器等于0时,将释放这个字符串所占据的内存,所以如果对该字符串多次引用,即使你认为自己释放了该字符串,只要refCnt大于零,Delphi就不会释放该字符串所占据的内存。
能力值:
( LV3,RANK:30 )
16 楼
多谢提醒,忘记了String是不好控制,我平时是这样来做的,如果按楼主的要求,就先定义一个array of byte,先用Move把Esi指向的字符串复制到Buf去,然后再用下面这个函数提取String出来,这样应该能解决了吧~
var
Buf:array [0..255] of byte;
str:=BytesToString(Buf,0,Count);
function BytesToString(Bytes: array of Byte; StartPos, Len: Integer): string;
var
I: Integer;
TmpStr: string;
begin
TmpStr:='';
for I:=StartPos to StartPos+Len-1 do
if (Bytes[I]=0) then
begin
Result:=TmpStr;
Exit;
end
else
TmpStr:=TmpStr+Char(Bytes[I]);
Result:=TmpStr;
end;