Дизассемблер длин x86 инструкций для сплайсинга

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by slesh, 14 Nov 2010.

  1. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Когда потребовалось написать модуль для сплайсинга определенных функций, и вот для него потребовался дизассемблер длин инструкций. В принципе функции которые надо было сплайсить не юзали mmx и sse а только x86 команды.

    Когда начал искать диасм длин, то находил довольно объемный, а иногда и стрёмный код, к томуже содержащий не нужный баласт в роле примочек связанных с mmx.

    При этом был найден довольно маленький диасм длин написанный на ассемблере.

    И так вот: за основу был взят VirXasm32 v1.5b (X) Malum 2006, код был портирован под Си (для MS Visual C++) в виде асм вставки и функции обертки для более удобного использования. Кстати, код поддерживает и MMX инструкции вроде как. потому что нормально определял их длинну

    Выкладываю сюда, может комунить пригодиться.
    Предоставляются 2 функции
    1) int MDAL_GetOpcodesLenByNeedLen(BYTE* opcode, int NeedLen);
    На входе:
    * адрес начала кода
    * минимальная требуемая длинна. На выходе -
    На выходе: кол-во байт больше минимально требуемого, но составляющих целое кол-во инструкций. Или 0 - ошибка.

    2) int _cdecl MDAL_GetOpcodeLen(BYTE* opcode);
    На входе: адрес кода
    На выходе: длинна первой инструкции. 0 = ошибка

    Вот непосредственно код:
    Code:
    #include <windows.h>
    
    #define _SALC	0xD6
    #define _AAM	0xD4
    #define NRM_TAB_LEN	53
    
    #define DB __asm _emit
    
    int MDAL_GetOpcodesLenByNeedLen(BYTE* opcode, int NeedLen)
    {
    	int FullLen = 0;
    	int len;
    
    	do
    	{
    		len = MDAL_GetOpcodeLen(opcode + FullLen);
    		if (!len)
    		{
    			return 0;
    		}
    		FullLen += len;
    	}
    	while (FullLen < NeedLen);
    
    	return FullLen;
    }
    
    __declspec(naked) int _cdecl MDAL_GetOpcodeLen(BYTE* opcode)
    {
    	_asm
    	{
    		mov esi, [esp + 4]
    		pushad
    		push	000001510h
    		push	0100101FFh
    		push	0FFFFFF55h
    		push	0FFFFFFF8h
    		push	0F8FF7FA0h
    		push	00F0EC40Dh
    		push	007551004h
    		push	001D005FFh
    		push	0550D5D55h
    		push	0555F0F88h
    		push	0F3F3FFFFh
    		push	00A0C1154h
    		
    		mov	edx, esi
    		mov	esi, esp
    
    		push	11001b
    		push	10110000101011000000101110000000b
    		push	10111111101100011111001100111110b
    		push	00000000000100011110101001011000b
    		mov	ebx, esp
    		sub	esp, 110
    		mov	edi, esp
    
    		cld
    		push	100
    		pop	ecx
    	xa_nxtIndx:
    		bt	[ebx], ecx
    		DB _SALC
    			
    		jnc	xa_is0
    		lodsb
    	xa_is0:
    		stosb
    		loop	xa_nxtIndx
    		mov	esi, edx
    
    		push	2
    		pop	ebx
    		mov	edx, ebx
    	xa_NxtByte:
    		lodsb
    		push	eax
    		push	eax
    		cmp	al, 66h
    		cmove	ebx, ecx
    		cmp	al, 67h
    		cmove	edx, ecx
    		cmp	al, 0EAh
    		je	xa_jmp
    		cmp	al, 09Ah
    		jne	xa_nocall
    
    		inc	esi
    	xa_jmp:
    		lea	esi, [esi+ebx+3]
    	xa_nocall:
    		cmp	al, 0C8h
    		je	xa_i16
    		and	al, 0F7h
    		cmp	al, 0C2h
    		jne	xa_no16
    	xa_i16:
    		inc	esi
    		inc	esi
    
    	xa_no16:
    		and	al, 0E7h
    		cmp	al, 26h
    		pop	eax
    		je	xa_PopNxt
    		cmp	al, 0F1h
    		je	xa_F1
    		and	al, 0FCh
    		cmp	al, 0A0h
    		jne	xa_noMOV
    		lea	esi, [esi+edx+2]
    	xa_noMOV:
    		cmp	al, 0F0h
    		je	xa_PopNxt
    	xa_F1:
    		cmp	al, 64h
    	xa_PopNxt:
    		pop	eax
    		je	xa_NxtByte
    
    		mov	edi, esp
    		push	edx
    		push	eax
    		cmp	al, 0Fh
    		jne	xa_Nrm
    		lodsb
    	xa_Nrm:
    		pushfd
    		DB _AAM
    		DB 10h
    		xchg	cl, ah
    		cwde
    		cdq
    		xor	ebp, ebp
    		popfd
    		jne	xa_NrmGroup
    
    		add	edi, NRM_TAB_LEN
    		jecxz	xa_3
    	xa_1:
    		bt	[edi], ebp
    		jnc	xa_2
    		inc	edx
    	xa_2:
    		inc	ebp
    		loop	xa_1
    		jc	xa_3
    		DB _SALC
    		cdq
    	xa_3:
    		shl	edx, 1
    		jmp	xa_ProcOpcode
    
    	xa_NrmGroup:
    		sub	cl, 4
    		jns	xa_4
    		mov	cl, 0Ch
    		and	al, 7
    	xa_4:
    		jecxz	xa_4x
    	xa_5:
    		adc	dl, 1
    		inc	ebp
    		bt	[edi], ebp
    		loop	xa_5
    		jc	xa_ProcOpcode
    	xa_4x:
    		shr	al, 1
    
    	xa_ProcOpcode:
    		xchg	cl, al
    		lea	edx, [edx*8+ecx]
    		pop	ecx
    		pop	ebp
    		bt	[edi+2], edx
    		jnc	xa_noModRM
    
    		lodsb
    		DB _AAM
    		DB 8
    		shl	ah, 4
    		jnc	xa_isModRM
    		js	xa_enModRM
    	xa_isModRM:
    		pushfd
    		test	ebp, ebp
    		jnz	xa_addr32	
    		sub	al, 6
    		jnz	xa_noSIB
    		mov	al, 5
    	xa_addr32:
    		cmp	al, 4
    		jne	xa_noSIB
    		lodsb
    		and	al, 7
    	xa_noSIB:
    		popfd
    		jc	xa_iWD
    		js	xa_i8
    		cmp	al, 5
    		jne	xa_enModRM
    	xa_iWD:	
    		add	esi, ebp
    		inc	esi
    	xa_i8:
    		inc	esi
    
    	xa_enModRM:
    		test	ah, 60h
    		jnz	xa_noModRM
    		xchg	eax, ecx
    		cmp	al, 0F6h
    		je	xa_ti8
    		cmp	al, 0F7h
    		jne	xa_noModRM
    		add	esi, ebx
    		inc	esi
    	xa_ti8:
    		inc	esi
    
    	xa_noModRM:
    		shl	edx, 1
    		bt	[edi+2+17], edx
    		jnc	xa_Exit
    		inc	edx
    		bt	[edi+2+17], edx
    		jnc	xa_im8
    		adc	esi, ebx
    	xa_im8:
    		inc	esi
    
    	xa_Exit:
    		add	esp, 110+64
    		sub	esi, [esp+4]
    		mov	[esp+7*4], esi
    		popad
    		ret
    	}
    }
    
    
    Размер непосредственно функции подсчета длинны текущей команды - 352 байта.
    Так что очень удобно юзать во всяком малваре, без особого увеличения размера

    Для особых извращенцев в аттаче лежит готовая DLL (1024 байта размер).
    Экспортирующая функцию
    int __stdcall GetOpcodeLen(unsigned char * opcode, int NeedLen);
    где
    1) opcode - адрес начала кода
    2) NeedLen - минимальное кол-во байт которое должно быть. Если поставить 0, то функция вернет длину первой команды.
    3) функция возвращает или длину инструкции/й или 0 в случае ошибки

    В делфи можно юзать так:

    function GetOpcodeLen(Opcode : pointer; NeedLen : integer):integer; stdcall; external 'opclen.dll' name 'GetOpcodeLen';
     

    Attached Files:

    #1 slesh, 14 Nov 2010
    Last edited: 14 Nov 2010
    1 person likes this.
  2. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    slesh
    создай oplen.obj чтоб от языка не зависел )
     
    #2 greki_hoy, 14 Nov 2010
    Last edited: 14 Nov 2010
  3. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    2slesh
    с /O1 esi сбивается после вызова MDAL_GetOpcodeLen
    у меня в црт вызывались конструкторы а в них ставились хуки при ините проги а там как раз цикл пробегается по массиву указателей после вызова первого остальные отдыхали если оптимизацию включал
    Code:
    void f0()
    {
        /* вот тут без оптимизации спасает что
         компиль сохраняет сам esi */
        call MDAL_GetOpcodeLen
        /* после вызова он сбит но в дебаге восстанавливается */
    }
    
    voif f1()
    {
        /* before use esi */  
        call f0();
        /* after use bad esi 
       тут глючит код с /O1 скомпиленный */
    }
    
    я так изменил и юзаю
    void f0()
    {
        __asm
    	{
    		push   esi
    		...
    		call   MDAL_GetOpcodeLen
    		...
    		pop    esi
    	}
    }
    
     
    #3 greki_hoy, 4 Jul 2011
    Last edited: 9 Jul 2011
  4. sn0w

    sn0w Статус пользователя:

    Joined:
    26 Jul 2005
    Messages:
    1,023
    Likes Received:
    1,310
    Reputations:
    327
    zombie disasm, 2кб - 2 таблицы и сам код байт 500, от мс компилера без оптимизаций
     
  5. sn0w

    sn0w Статус пользователя:

    Joined:
    26 Jul 2005
    Messages:
    1,023
    Likes Received:
    1,310
    Reputations:
    327
    о а ща по ситуации плюсую, вообщем в базонезависимом шеллкоде нужен сплайс, я сперва подумал, один хрен почти везде в апи mov edi,edi push ebp mov ebp,esp; но для универсальности добавлю, грац!
     
  6. mirvirusov

    mirvirusov New Member

    Joined:
    11 Jun 2021
    Messages:
    29
    Likes Received:
    3
    Reputations:
    0
    С поддержкой 64 есть сейчас что на примете ?