سؤال

حسنًا، أنا أدرس بعض عمليات التجميع المضمّنة في دلفي، وكل روتين تجميع التشفير يسير على ما يرام، حتى أحاول تحليل ShortString في Textbox.

المخالفة التي حصلت عليها هي كما يلي:Error

الكود الكامل هنا:

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;

مع تشغيل التحسينات، فإن كود المجمع الذي تم إنشاؤه بواسطة هذا هو في الواقع أقصر مقارنة بالكود المقترح، ولا يحتوي على كود زائد وأنا على استعداد للمراهنة على أنه أسرع.فيما يلي بعض التحسينات التي لاحظتها في التعليمات البرمجية التي تم إنشاؤها بواسطة دلفي (مقارنة بكود المجمّع الذي اقترحه OP):

  • عكست دلفي الحلقة (وصولاً إلى 0).يؤدي هذا إلى حفظ تعليمة "CMP" واحدة لأن المترجم يمكنه ببساطة "DEC ESI" والتكرار على علامة الصفر.
  • تم استخدام "XOR EDX" و"DIV EBX" للقسم الثاني، مما يوفر قدرًا صغيرًا من الدورات.

لماذا يفشل رمز المجمع المقدم؟

هذا هو كود المجمع الأصلي، مع التعليقات.الخطأ موجود في نهاية الروتين، في تعليمات "CMP" - فهو يقارن ESI بطول المفتاح، وليس بطول الاسم.إذا كان المفتاح أطول، فإن الاسم، فإن "التشفير" يستمر فوق الجزء العلوي من الاسم، مما يؤدي إلى الكتابة فوق الأشياء (من بين الأشياء التي يتم الكتابة فوقها هو فاصل NULL للسلسلة، مما يتسبب في قيام مصحح الأخطاء بإظهار أحرف مضحكة بعد الأحرف الصحيحة).

على الرغم من أن الكتابة فوق 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 سنتًا

ينبغي استخدام المجمع ل تحسينات السرعة ولا شيء غير ذلك.يبدو لي كما لو أن OP حاول استخدام المجمع للتعتيم على ما يفعله الكود.لم يساعدني الأمر، فقد استغرق الأمر مني بضع دقائق فقط لأكتشف بالضبط ما يفعله الكود وأنا لا خبير المجمع.

نصائح أخرى

أولا، تحتاج إلى الحفاظ على EDI و ESI.فقط EAX، EDX، و ECX، يمكن استخدامها دون الحفاظ (باستثناء عند تحميلها وتحتاج إلى الحفاظ عليها).

حاول إضافة بعض دفع EDI، ودفع ESI و POP ESI، POP EDI حول التعليمات البرمجية الخاصة بك.

لا يمكنك ببساطة اختيار السجلات لأغراضك الخاصة في ASM المضمنة دون الحفاظ على محتويات التسجيل (توفير واستعادة).

في التعليمات البرمجية، تقوم بتدبيرها على EAX (والتي تحمل "الذات") و EDX (والتي - مع "تسجيل " اتفاقية الاتصال - على الأرجح "المرسل").

وكما أفهم أنه قد يتم استخدام سجلات أخرى أيضا للمتغيرات المحلية.

تلميح: ماذا لو كان Esi أو EAX أو كل ما يحمل نفسه؟مجمع الخاص بك القمامة.السطر التالي الذي تحاول استخدام Edit2، والذي يتطلب الوصول إلى الذات، وهو ... حسنا، لم يعد معنا.

compiler واستخدام السجلات.تحتاج إلى لعب لطيف والتعاون مع التحويل البرمجي، مما يعني توفير / استعادة قيم السجلات ".

خلاف ذلك، أعتقد أنك بحاجة إلى تفصيل رمز المجمع لفصل الروتين، لذلك لن يكون هناك رمز Pascal، مما قد يستخدم السجلات أيضا.ملاحظة، ستظل تحتاج إلى مطابقة بروتوكول الاتصال بالاتصال: لا يمكن استخدام جميع السجلات بحرية.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top