Pergunta

Bem, estou estudando algumas assembly embutido em Delphi e a assembleia de criptografia de rotina é tudo indo muito bem, até eu tentar analisar o ShortString para a caixa de Texto.

A violação de eu chegar é o seguinte:Error

O código completo está aqui:

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;

Se eu colocar um ponto de interrupção na linha "edit2.Texto:= TCaption(chave);" eu posso ver que o ShortString "chave" de fato foi devidamente encriptados, mas com um monte de caracteres estranhos, por trás dele, também.

Os primeiros 16 caracteres é o real de criptografia.

criptografia http://img831.imageshack.us/img831/365/29944312.png

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

obrigado!

Foi útil?

Solução

O que faz o código

Para aqueles de vocês que não falam assembler, isso é o que o código está provavelmente deveria fazer, em Pascal."Provavelmente" porque o original contém alguns erros:

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;

Com otimizações ativada, o montador código gerado por este, na verdade, é mais curto em comparação com a proposta de código, não contém nenhum código redundante e estou disposto a apostar que é mais rápido.Aqui estão algumas otimizações que eu notei em Delphi-o código gerado (comparado com o código assembler proposta pelo OP):

  • Delphi inverteu o ciclo (downto 0).Isso economiza um "CMP" instrução porque o compilador pode simplesmente "DEZ ESI" e laço no zero bandeira.
  • Usado "XOR EDX" e "DIV EBX" para a segunda divisão, economizando um pouco de pequena quantidade de ciclos.

Por que é fornecido código assembler falhando?

Aqui está o original do código assembler, com comentários.O erro está no fim da rotina, o "CMP" de instrução - que é a comparação de RSE para o comprimento da CHAVE, não para o comprimento do NOME.Se a CHAVE é mais longo do que o NOME, "criptografia" vai em cima do NOME, substituindo coisas (entre as coisas que são substituídas é o terminador NULO para a cadeia, fazendo com que o depurador para mostrar engraçado caracteres após o correto caracteres).

Enquanto a substituição EBX e a RSE não é permitido, não é isso que está causando o código para AV, provavelmente, porque o entorno do código do Delphi não usar EBX ou ESI (apenas tentei isso).

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.

Meus 2 centavos de conselhos

Montador deve ser usado para Otimizações de VELOCIDADE e nada mais.Ele olha para mim como se o OP tentou usar Assembler, para ocultar o que o código está fazendo.Não ajuda, somente ele me levou alguns minutos para descobrir exatamente o que o código está a fazer e eu estou NÃO um montador de especialistas.

Outras dicas

Primeiro, você precisa para preservar EDI e ESI.Só EAX, EDX, e ECX, pode ser usado sem conservação (exceto quando você carregá-lo e precisamos preservá-la).

Tente adicionar um pouco de tentativa de EDI, emissão ESI e POP ESI, POP EDI em torno de seu código.

Você não pode simplesmente cooptação de registos para os seus próprios fins no inline ASM sem preservar (salvar e restaurar) o registo conteúdo.

No seu código você está menosprezando EAX (que tem "auto") e EDX (que - com o padrão registar convenção de chamada - o mais provável possui "Remetente").

E como eu a entendo outros registros também podem ser usados para variáveis locais.

Dica:o que se ESI ou EAX ou o que quer que detém Auto?O montador lixo.Próxima linha que você está tentando usar Edit2, que requer o acesso ao Self, que é...bem, não mais com a gente.

Tanto o compilador e você registos de utilização.Você precisa jogar bonito e cooperar com o compilador, o que significa guardar/restaurar registra os valores.

Caso contrário, eu acho que você precisa de descarregamento de código assembler para separar rotina, assim não haverá nenhum código Pascal, que poderão utilizar registros também.Note que você ainda precisa para se conformar convenção de chamada protocolo:nem todos os registradores podem ser usados livremente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top