문제

델파이에서 일부 인라인 어셈블리를 공개하고 있습니다. TextBox로 쇼트 스트링을 구문 분석하려고 할 때까지 Adminally Crypto 루틴이 모두 훌륭합니다.

i 위반은 다음과 같습니다. 오류

전체 코드는 다음과 같습니다.

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 (키) 줄에 중단 점을 배치하면"나는 쇼트 스트링 "키"가 실제로 적절하게 암호화되었지만 그 뒤에있는 이상한 문자가 많이 있음을 알 수 있습니다.

처음 16자는 실제 암호화입니다.

암호화 http://img831.imageshack.us/img831/365/29944312.PNG

bigger version: http://img831.imageshack.us/img831/365/29944312.png
.

감사합니다!

도움이 되었습니까?

해결책

코드가 수행하는

어셈블러를 말하지 않는 사용자를 위해, 이것은 파스칼에서 코드가 수행 해야하는 것입니다. "아마"원래에는 몇 가지 버그가 포함되어 있기 때문에 :

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;
.

최적화가 켜지면, 이로 인해 생성 된 어셈블러 코드는 제안 된 코드와 비교하여 실제로 짧고 중복 코드가 포함되어 있지 않으므로 BET를 기꺼이 빠릅니다. 다음은 델파이 생성 된 코드 (op 에서 제안한 어셈블러 코드와 비교하여 )에서 알아 차리는 몇 가지 최적화입니다.

  • 델파이는 루프를 반전 (0). 이렇게하면 컴파일러가 단순히 "DEC ESI"와 0 플래그에서 루프 할 수 있으므로 하나의 "CMP"명령을 저장합니다.
  • 는 두 번째 부분에 대해 "XOR EDX"및 "Div EBX"를 사용하여 일부 크기의 사이클을 저장합니다.

제공된 어셈블러 코드가 실패한 이유는 무엇입니까?

여기에 댓글이있는 원래 어셈블러 코드가 있습니다. 버그는 "CMP"명령어에서 루틴의 끝 부분에 있으며 이름의 길이가 아니라 ESI를 키의 길이로 비교합니다. 키가 더 길면 "암호화"가 이름의 맨 위에 올라가는 것, (겹쳐 쓰는 것으로 덮여있는 것들 중에서 널렌 터미네이터가 올바른 chars 이후에 재미있는 문자를 표시하도록)됩니다.

EBX와 ESI를 덮어 쓰지 않는 동안, 이것은 코드를 AV로 인한 것인지 아마도 주변 델파이 코드가 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 센트의 가치가있는

어셈블러는 속도 최적화 및 else 에 대해 사용해야합니다. OP가 어셈블러를 사용하여 코드가 무엇을하고 있는지를 난독 화하기 위해 어셈블리를 사용하려고했는지처럼 보입니다. 도움이되지 않았고, 코드가 무엇을하고 있는지 정확히 알아낼 수있는 몇 분이 걸렸습니다. 어셈블러 전문가가 아닙니다.

다른 팁

첫째, EDI와 ESI를 보존해야합니다.EAX, EDX 및 ECX 만 보존하지 않고 사용할 수 있습니다 (당신이 그것을로드하고 그것을 보존 해야하는 경우를 제외하고).

일부 푸시 EDI를 추가하고 ESI를 누르고 POP ESI를 누르고 코드 주위에 POP EDI를 누릅니다.

레지스터 내용을 유지 (저장 및 복원)하지 않고도 인라인 ASM에서 자신의 목적을위한 레지스터를 공동으로 꺼냅니다.

코드의

(자체 "를 보유하고 있으며 EDX)와 EDX (기본 레지스터 대부분"보낸 사람 "보류)

및 IT를 이해할 때 다른 레지스터가 로컬 변수에도 사용될 수도 있습니다.

힌트 : ESI 또는 eax 또는 뭐든간에 무엇이든지 뭐지?어셈블러가 쓰레기통을 쓰고 있습니다.다음 줄 당신은 Edit2를 사용하려고 노력하고 있습니다. 이는 자아에 대한 액세스가 필요합니다. 그것은 더 이상 우리와 함께하지 않습니다.

모두 컴파일러와 레지스터를 사용합니다.컴파일러와 협력하여 등록을 저장 / 복원하는 것을 의미합니다.

그렇지 않으면 루틴을 분리하기 위해 어셈블러 코드를 오프로드해야한다고 생각하므로 Pascal 코드가 없으므로 레지스터도 사용할 수 있습니다.통제 규칙 프로토콜을 준수해야합니다. 모든 레지스터가 자유롭게 사용할 수있는 것은 아닙니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top