mov edi, edi

Reverse Code Engineering 2009.09.15 20:44 posted by jz-
DLL을 리버싱하다 보면 export된 함수에 hot patch를 위한 +2byte, -5byte가 있죠.




이는 API 시작에 EB F9 (JMP SHORT $-5)를 넣고, 위 5바이트에 또 JMP/CALL을 넣을 수 있게 만들어준 것입니다.(hot patch)
참고 : http://blogs.msdn.com/ishai/archive/2004/06/24/165143.aspx


왜 mov edi, edi일까, 왜 mov eax, eax / mov esi, esi도 아닌 edi 일까란 의문이 fullc0de님이랑 잡담하다가 튀어나왔지만 뭐 "nop보다는 보기 좋으니까" 말고는 결론이 안났습니다. ㅋㅋ

[그리고 혹시 vs나 platform sdk에서 저 바이너리를 넣는 옵션이 어떤건지 아는 분 계시면 알려주시면 감사하겠습니다.]

아무튼 이 binary를 모든 exported system dll apis 가 갖고 있을까? 란 의문이 들었습니다. (물론 Zw* 제외)

결론은 아니더군요.

코드와 기타 라이브러리, 결과입니다. (압축암호:'봇방지')

궁금한 dll은 argument로 주면 알아서 로드하고 조사합니당.

#include 
#include 
#include 
#include "pework.h"
#include "undocumented.h"
#include "disasm.h

BYTE ck1[] = "\x90\x90\x90\x90\x90\x8b\xff";		// nop * 5 + mov edi, edi

void main( int argc, char **argv )
{
	_PEB2 *peb;
	pework pe;
	dll_list_entry *entry;
	IMAGE_EXPORT_DIRECTORY *exp;
	int i, j, k;

	if( argc != 1 )
	{
		for( i = 1; i < argc; i ++ )
			LoadLibrary( argv[i] );
	}

	_dis_data dis;

	_asm{
		mov edx, dword ptr fs:[0x30]
		mov peb, edx
	}

	entry = ((dll_list_entry*)peb->LoaderData->InLoadOrderModuleList.Flink->Flink);

	while( entry && (entry->imagebase) )
	{
		if( pe.OpenBuffer( (BYTE*)entry->imagebase, 0x1000 ) == FALSE )
		{
			wprintf( L"%s", entry->uniModuleName.Buffer );
			break;
		}

		exp = (IMAGE_EXPORT_DIRECTORY*)( pe.GetNH()->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + pe.GetImageBase() );

		for( i = 0; i < (int)exp->NumberOfFunctions; i ++ )
		{
			void *func;
			func = (void*)( *(DWORD*)( exp->AddressOfFunctions + pe.GetImageBase() + (i*4) ) + pe.GetImageBase() );
			if( func == NULL )
				break;

			if( memcmp( (BYTE*)func - 5, ck1, 7 ) != 0 )
			{
				// mismatch found
				wprintf( L"mismatch in %s::", entry->uniModuleName.Buffer );
				printf( "%s\n", (char*)( *(DWORD*)( exp->AddressOfNames + (i*4) + pe.GetImageBase() ) + pe.GetImageBase() ) );

				DWORD offset = 0;
				DWORD len;
				for( j = 0; j < 7; j ++ )
				{
					if( *(BYTE*)( (DWORD)func + offset - 5 ) == 0 )
					{
						printf( "\t00\n" );
						offset ++;
						continue;
					}

					len = _disasm( (BYTE*)( (DWORD)func + offset - 5 ), &dis );
					if( len == 0 )
						break;

					printf( "\t" );
					for( k = 0; k < (int)len; k ++ )
					{
						printf( "%02x ", *(BYTE*)( (DWORD)func + offset + k - 5 ) );
					}
					printf( "   " );
					printf( "%s\n", dis.instr_out );

					offset += len;
				}
			}
			else
			{
				wprintf( L"match in %s::", entry->uniModuleName.Buffer );
				printf( "%s\n", (char*)( *(DWORD*)( exp->AddressOfNames + (i*4) + pe.GetImageBase() ) + pe.GetImageBase() ) );
			}
		}

		entry = (dll_list_entry*)(entry->InLoadOrderModuleList.Flink);

	}
}






TAG
  1. Commented by chpie at 2009.09.17 09:41 신고

    오 아.. nop 5바이트를 저렇게 쓰는거였군요.
    저렇게 하면 빠개진 명령어를 복구할 필요도 없고 좋네요!!
    전 mov edi, edi 부터 mov ebp, esp 까지 해서
    5바이트에 jmp 를 삽입하는건줄 알았는데 ㅋㅋㅋ

    • Commented by jz at 2009.09.17 13:41 신고

      ㅋㅋ 그치 편하지 근데 문제는 저거 없는 api도 있다는거 ㅡㅡ; 없는건 기존방식으로 해야하나

  2. Commented by iwillhackyou at 2009.09.18 09:36 신고

    컴파일러, 링크 옵션은 /hotpatch, /functionpadmin을 사용하시면 됩니다.

    트랙백 걸고 갑니다~^^;