アセンブラーでクイン? ただ

quine(quine)はプログラムであり、その結果はプログラム自体のテキストの出力であることが知られています。 プログラムを含むファイルにはアクセスしないと想定されています。



Quinesは、ほとんどすべてのプログラミング言語でコンパイルできますが、一部のエキゾチックな言語は例外です。 プログラムをWin32アプリケーションにし、そのテキストをウィンドウに表示することを前提に、アセンブラーでクインをコンパイルするタスクを検討してください。



同じマシンコードは、アセンブラーで異なる方法で表現できます。 48をスタックにプッシュするとします。対応する2バイトの命令は、ニーモニックに記述できます。



48を押す(または30hを押す)、



およびdb dataディレクティブの使用



db 06Ah、030h(またはdb 106.48)。



オプションdb 'j0'も使用できます。 これらすべてのケースで、コンパイルの結果、同じマシンコードが生成されます。 命令のニーモニック表現を含むアセンブラクイーンを作成することは困難です。明らかに、プログラムの何千行も必要になります。 したがって、ガイドされる主なアイデアは、次の形式のdbディレクティブを使用してクインを取得することです。



ソース1



.386 .model flat,stdcall .code q: db 16-     .... db 16-     end q
      
      







(MASMアセンブラーが使用されます)。 難点は、そのようなクインを直接書くことはほとんど不可能であるということです-実際にはマシンコードでプログラミングしています。 ただし、通常のアセンブラニーモニックを使用してプログラムを作成することから始めることができます-以下のソース2を参照してください。



ソース2



 ; @echo off ; ml /c /coff quine.cmd ; pause ; if errorlevel 1 goto exit ; link /subsystem:windows /section:.text,RW quine.obj ; pause ; del quine.obj ; goto exit .386 .model flat,stdcall option casemap:none include \masm32\include\windows.inc bStr = 25 ; - ,      qLen = len * 5 + (len / bStr + 1) * 4 + len1 + 10 ;    stLen = (qLen / 1000h + 1) * 1000h ;       .code ; ***  1 -      *** start: cld mov edx,[esp] ;   kernel32.dll -   2 sub esp,stLen ;     mov edi,esp mov stAddr,edi lea esi,text xor ecx,ecx mov cl,len1 rep movsb ;   '.386 .model flat ...' lea esi,start mov bl,bStr cycl: mov eax,ecx ;  .  ? div bl or ah,ah jnz comma mov ax,0A0Dh ;  -      db stosw mov eax,' bd' stosd dec edi jmp j1 comma: mov al,',' ;  -  ,   stosb j1: mov al,'h' ;  16-   -  h shl eax,16 lodsb mov ah,al and al,0Fh cmp al,10 sbb al,69h das ;    xchg al,ah shr al,4 cmp al,10 sbb al,69h das ;   shl eax,8 mov al,'0' ;  0 stosd inc ecx cmp ecx,len jb cycl mov ax,0A0Dh ;   'end q' stosw mov eax,' dne' stosd mov eax,'q' stosd ; ***  2 -   API  *** xor dx,dx c2: cmp word ptr [edx],'ZM' ; MZ-  kernel32? je c1 c3: sub edx,10000h jmp c2 c1: mov ecx,[edx+3Ch] cmp dword ptr [edx+ecx],'EP' ; PE-? jne c3 mov ecx,[edx+ecx+78h] add ecx,edx ;    kernel32 push ecx mov eax,[ecx+20h] add eax,edx ;      xor ebx,ebx xor ecx,ecx cycl2: mov esi,[eax+4*ebx] add esi,edx lea edi,GPAname mov cl,len2 repe cmpsb ;   GetProcAddress je found inc ebx jmp cycl2 found: pop ecx mov eax,[ecx+24h] add eax,edx mov bx,[eax+2*ebx] ;   GetProcAddress mov eax,[ecx+1ch] add eax,edx mov ebx,[eax+4*ebx] add ebx,edx mov edi,edx ; EBX -  GetProcAddress ; EDI -   kernel32 (  - user32) xor ecx,ecx ;     mov cl,tlen lea esi,tbl cycl3: cmp cl,tlen-tlen2 jne j2 push ecx push offset DLLname call eax ;  user32.dll    LoadLibrary pop ecx mov edi,eax j2: dec cl push ecx push [esi+4*ecx] push edi call ebx ;      GetProcAddress pop ecx mov [esi+4*ecx],eax or cl,cl jnz cycl3 ; ***  3 -     MessageBox *** push NULL call dword ptr _GetModuleHandle mov hInst,eax call dword ptr _GetCurrentThreadId push eax push NULL push offset hProc push WH_CBT ;      call dword ptr _SetWindowsHookEx mov hook,eax push MB_OK push offset capt push stAddr push 0 call dword ptr _MessageBox ;     push 0 call dword ptr _ExitProcess ; *** hProc proc code:dword,wParam:dword,lParam:dword ;   local coord:RECT pusha cmp code,HCBT_ACTIVATE ;  ? jne exit push 0FFFFh push wParam call dword ptr _GetDlgItem mov ebx,eax ;    lea eax,coord push eax push ebx call dword ptr _GetClientRect ;    add coord.right,20 push NULL push NULL push WM_GETFONT push ebx mov edi,_SendMessage call edi ;    mov esi,eax push SW_HIDE push ebx call dword ptr _ShowWindow ;   push NULL push hInst push 0FFFFh push wParam push coord.bottom push coord.right push coord.top push coord.left push WS_CHILD+WS_VISIBLE+ES_MULTILINE+ES_READONLY push stAddr push offset cname push WS_EX_WINDOWEDGE call dword ptr _CreateWindowEx ;  EDIT  STATIC ;  ,       push NULL push esi push WM_SETFONT push eax call edi ;   push hook call dword ptr _UnhookWindowsHookEx ;   popa xor eax,eax ret exit: popa push lParam push wParam push code push hook call dword ptr _CallNextHookEx ;    ret hProc endp ; ***   capt db 'Quine',0 ;   GPAname db 'GetProcAddress',0 len2 equ $ - GPAname GDIname db 'GetDlgItem',0 ;    GCRname db 'GetClientRect',0 SMname db 'SendMessageA',0 SWname db 'ShowWindow',0 CWEname db 'CreateWindowExA',0 UWHEname db 'UnhookWindowsHookEx',0 CNHEname db 'CallNextHookEx',0 SWHEname db 'SetWindowsHookExA',0 MBname db 'MessageBoxA',0 LLname db 'LoadLibraryA',0 GMHname db 'GetModuleHandleA',0 GCTIname db 'GetCurrentThreadId',0 EPname db 'ExitProcess',0 DLLname db 'user32.dll',0 cname db 'EDIT',0 ;   text db '.386',13,10,'.model flat,stdcall',13,10,'.code',13,10,'q:' ;   len1 equ $ - text tbl label dword ;    ,     _GetDlgItem dd offset GDIname ;   user32.dll _GetClientRect dd offset GCRname _SendMessage dd offset SMname _ShowWindow dd offset SWname _CreateWindowEx dd offset CWEname _UnhookWindowsHookEx dd offset UWHEname _CallNextHookEx dd offset CNHEname _SetWindowsHookEx dd offset SWHEname _MessageBox dd offset MBname tbl2 label dword _LoadLibrary dd offset LLname ;   kernel32.dll _GetModuleHandle dd offset GMHname _GetCurrentThreadId dd offset GCTIname _ExitProcess dd offset EPname tlen2 equ ($-tbl2) / 4 tlen equ ($-tbl) / 4 ;   len equ $ - start ;   ; ***  ,     hInst dd ? ;   hook dd ? ;   stAddr dd ? ;      end start :exit
      
      







操作の原則は、本文のコメントから明らかです。 プログラムは3つの部分で構成されていることに注意してください。 最初の部分では、クインテキストがスタック(つまりソース1)に形成されます。 単一のdbディレクティブで定義されたバイト数(クイーン文字列の幅)は、bStr定数で設定されます-25に設定されます。 コンパイル中にAPI関数はインポートされないため、多くの関数のアドレスは2番目の部分で動的に決定されます。 まず、これは、kernel32.dllモジュールのエクスポートテーブルをトレースして取得したGetProcAddress関数のアドレスです。 次に、GetProcAddressを使用して取得した残りの関数のアドレス。 最後に、3番目の部分では、QuineがMessageBoxウィンドウに出力されます。 デフォルトのテキストは静的であり、どこにもコピーできないため、ウィンドウからテキストをコピーできる追加のフックがインストールされます。 たとえば、メッセージキューを作成してウィンドウ関数を作成するなど、クインの3番目の部分には他のオプションがあります。



したがって、ソース2(クインではありません)をバッチファイルquine.cmdに保存して実行する必要があります-実行可能ファイルquine.exeになります。 次に、quine.exeが起動し、表示されたウィンドウからマウスを選択して、テキストをquine.asmファイルにコピーします。 実行可能ファイルは削除できます。 したがって、quine.asm-完全なクイン(ソース1を参照)。 を使用して放送されます



ml / c / coff quine.asm



しかし、とリンク



リンク/サブシステム:windows /section:.text,RW quine.obj



(コードセクションで書き込みが許可されている必要があります)。 コードのlenセクションは820バイトでした。



ターボデバッガーでプログラムをデバッグしましたが、同時に次の行も含まれていました



ExitProcessを呼び出す、0



エントリポイントの開始前(他の機能を使用できます)、および行



include \ masm32 \ include \ kernel32.inc

includelib \ masm32 \ lib \ kernel32.lib



そうしないと、デバッガーがフリーズします-明らかに、実行可能ファイルにインポートテーブルがないためです。



All Articles