我得到的违规行为如下:
Error http://img828.imageshack.us/img828/2410/43832949.png
完整代码在这里:
procedure TForm2.Button1Click(Sender: TObject); var len,keylen:integer; name, key:ShortString; begin name := ShortString(Edit1.Text); key := '_r <()<1-Z2[l5,^'; len := Length(name); keylen := Length(key); nameLen := len; serialLen := keyLen; asm XOR EAX,EAX XOR ESI,ESI XOR EDX,EDX XOR ECX,ECX @loopBegin: MOV EAX,ESI PUSH $019 CDQ IDIV DWORD PTR DS:[serialLen] MOV EAX,ESI POP EBX LEA ECX,DWORD PTR DS:[key+EDX] CDQ IDIV DWORD PTR DS:[nameLen] LEA EAX,DWORD PTR DS:[name] MOVZX EAX,BYTE PTR DS:[name+EDX] MOVZX EDX,BYTE PTR DS:[ECX] XOR EAX,EDX CDQ IDIV EBX ADD DL,$041 INC ESI CMP ESI,DWORD PTR DS:[serialLen] MOV BYTE PTR DS:[ECX],DL JL @loopBegin end; edit2.Text:= TCaption(key); end;
如果我在“edit2.Text:= TCaption(key);”行上放置一个断点我可以看到ShortString“key”确实已经被正确加密了,但它背后也有许多奇怪的字符.
前16个字符是真正的加密.
encryption http://img831.imageshack.us/img831/365/29944312.png
bigger version: http://img831.imageshack.us/img831/365/29944312.png
谢谢!
代码的作用对于那些不会说汇编程序的人来说,这就是代码可能应该做的事情,在Pascal中. “可能”因为原文包含一些错误:
procedure TForm14.Button1Click(Sender: TObject); var KeyLen:Integer; Name, Key:ShortString; i:Integer; CurrentKeyByte:Byte; CurrentNameByte:Byte; begin Name := ShortString(Edit1.Text); Key := '_r <()<1-Z2[l5,^'; keyLen := Length(key); asm int 3 end; // This is here so I can inspect the assembler output in the IDE // for the "Optimised" version of the code for i:=1 to Length(Name) do begin CurrentKeyByte := Byte(Key[i mod KeyLen]); CurrentNameByte := Byte(Name[i]); CurrentNameByte := ((CurrentKeyByte xor CurrentNameByte) mod $019) + $041; Name[i] := AnsiChar(CurrentNameByte); end; Caption := Name; end;
启用优化后,由此生成的汇编代码实际上比建议的代码更短,不包含冗余代码,我愿意打赌更快.以下是我在Delphi生成的代码中注意到的一些优化(与OP提出的汇编代码相比):
>德尔福扭转了循环(下降0).这节省了一条“CMP”指令,因为编译器可以简单地“DEC ESI”并循环零标志.
>第二部分使用“XOR EDX”和“DIV EBX”,节省了一些微小的周期.
为什么提供的汇编程序代码失败?
这是原始汇编代码,带有注释.例程结束时的错误,在“CMP”指令处 – 它将ESI与KEY的长度进行比较,而不是NAME的长度.如果KEY比NAME长,则“加密”继续在NAME的顶部,覆盖内容(被覆盖的内容之一是字符串的NULL终止符,导致调试器在正确的字符后显示有趣的字符).
虽然不允许覆盖EBX和ESI,但这并不是导致AV代码的原因,可能是因为周围的Delphi代码没有使用EBX或ESI(只是试过这个).
asm XOR EAX,EAX ; Wasteful, the first instruction in Loop overwrites EAX XOR ESI,ESI XOR EDX,EDX ; Wasteful, the first CDQ instruction in Loop overwrites EDX XOR ECX,ECX ; Wasteful, the first LEA instruction overwrites ECX @loopBegin: ; Etering the loop, ESI holds the index for the next char to be ; encrypted. MOV EAX,ESI ; Load EAX with the index for the next char, because ; we intend to do some divisions (setting up the call to IDIV) PUSH $019 ; ? pushing this here, so we can pop it 3 lines later... obfuscation CDQ ; Sign-extend EAX (required for IDIV) IDIV DWORD PTR DS:[serialLen] ; Divide EAX by the length of the key. MOV EAX,ESI ; Load the index back to EAX, we're planning on an other IDIV. Why??? POP EBX ; Remember the PUSH $019? LEA ECX,DWORD PTR DS:[key+EDX] ; EDX is the result of "ESI mod serialLen", this ; loads the address of the current char in the ; encryption key into ECX. Dividing by serialLen ; is supposed to make sure we "wrap around" at the ; end of the key CDQ ; Yet some more obfuscation. We're now extending EAX into EDX in preparation for IDIV. ; This is obfuscation becasue the "MOV EAX, ESI" instruction could be written right here ; before the CDQ. IDIV DWORD PTR DS:[nameLen] ; We divide the current index by the length of the text ; to be encrypted. Once more the code will only use the reminder, ; but why would one do this? Isn't ESI (the index) always supposed to ; be LESS THEN nameLen? This is the first sign of trouble. LEA EAX,DWORD PTR DS:[name] ; EAX now holds the address of NAME. MOVZX EAX,BYTE PTR DS:[name+EDX] ; EAX holds the current character in name MOVZX EDX,BYTE PTR DS:[ECX] ; EDX holds the current character in Key XOR EAX,EDX ; Aha!!!! So this is an obfuscated XOR loop! EAX holds the "name[ESI] xor key[ESI]" CDQ ; We're extending EAX (the XOR result) in preparation for a divide IDIV EBX ; Divde by EAX by EBX (EBX = $019). Why???? ADD DL,$041 ; EDX now holds the remainder of our previous XOR, after the division by $019; ; This is an number from $000 to $018. Adding $041 turns it into an number from ; $041 to $05A (ASCII chars from "A" to "Z"). Now I get it. This is not encryption, ; this is a HASH function! One can't un-encrypt this (information is thrown away at ; the division). INC ESI ; Prep for the next char ; !!! BUG !!! ; ; This is what's causing the algorithm to generate the AV. At this step the code is ; comparing ESI (the current char index) to the length of the KEY and loops back if ; "ESI < serialLen". If NAME is shorter then KEY, encryption will encrypt stuff beyond ; then end of NAME (up to the length of KEY). If NAME is longer then KEY, only Length(Key) ; bytes would be encrypted and the rest of "Name" would be ignored. ; CMP ESI,DWORD PTR DS:[serialLen] MOV BYTE PTR DS:[ECX],DL ; Obfuscation again. This is where the mangled char is written ; back to "Name". JL @loopBegin ; Repeat the loop.
我的2美分的建议
汇编程序应该用于SPEED优化而不是其他任何东西.它看起来好像OP试图使用Assembler来模糊代码所做的事情.没有帮助,我花了几分钟才弄清楚代码到底在做什么,我不是一个汇编专家.