반응형
Tsearch 한글 수정판 bisket 2

한글로 패치한 Tsearch 와 동일한 프로그램이다.



반응형

레지스터에 어느정도 감을 잡으셧다면 명령어를 좀 외워두어야 겠죠 ?

프로그램은 명령하는 코드가 집합되 있는거 뿐이니까요 ^ㅡ^

명령의 개략적인 해설 입니다.


데이터 전송 명령:    MOV


사칙연산 명령   :    ADD: 덧셈, ADC: 덧셈, SUB: 뺄셈, SBB: 뺄셈

                     MUL: 곱셈, IMUL: 부호달린 곱셈,

                     DIV: 나눗셈, IDIV: 부호달린 나눗셈

                     CBW: 바이트에서 워드로 부호확장

                     CWD: 워드에서 더블워드로 부호확장

                     INC: 하나 증가

                     DEC: 하나 감소  


논리연산, 쉬프트명령:AND: 논리곱, OR: 논리합,

                     XOR: 배타적 논리합, NOT:부정, NEG: 부호반전    

                     SHL: S는 shift, H는 0을 넣을 것인가, L은 left

                     ROR: R은 Rotate,


비교분기 명령: CMP, JMP는 무조건 분기,

                     Above(크다), Below(작다), Greater(부호를 포함해서 크다.)

                     Less(부호를 포함해서 작다), Equal(같다), Not(부정)

                     LOOP: 반복

                     LOOPE: loop if equal     ----+ 조건부 반복

                     LOOPNE: loop if not equal ---+

                     CALL: 서브루틴으로 분기      

                     RET:  서브루틴으로부터 원래의 루틴으로 돌아올 때


스트링 명령:         LODS: 메모리로부터 레지스터에 데이터를 로드

                     STOS: 메모리에 데이터를 저장하는 명령  

                    LODS, STOS는 메모리의 번지지정 방법이 SI 혹은 DI레지스터를 사용하여 간접지정으로 정해지기 때문에 미리 SI, DI에 번지를 세트해 두어야 하죠.

                     LODSB, STOSW, MOVSB, MOVSW: 블럭전송, 단독으로 1바이트, 1워드의 데이터를 전송

                     RET(repeat) 명령과 조합시켜 사용하면 cx 레지스터가 지정하는 횟수만큼 반복하여 데이터를 전송합니다.

                     이때 번지는 자동으로 갱신되어가므로 한 명령으로 연속된 여러 데이터를 전송할 수가 있습니다.``


스트링 명령에는 그 밖에도 데이터의 전송은 하지 않고 레지스터와 메모리의 내용을  

                     비교만 하는 SCAS(scan string),

                     메모리끼리의 내용을 비교하는 CMPS(compare string)

                     이들 명령은 REPE(repeat until equal)

                     REPNE(repeat until not equal)명령과 조합함으로써 일치하는 데이터가 얻어질 때까지, 혹은 일치하지 않는 데이터가 얻어질 때까지, 메모 리상의 데이터를 탐색할 수가 있습니다.


                     SCASB

                     REPE       SCASW

                     REPNE      CMPSB

                     REPE       CMPSW


I/O 명령: LSI에 명령을 보낸다든지 데이터를 얻는다든지 하기 위한 명령이 I/O 명령

                     I/O 포트에 데이터를 보내는 명령이 OUT

                     I/O 포트에 데이터를 얻는 명령이 IN

                     포트의 번호는 직접 수치 혹은 DX 레지스터를 사용하여 지정

                     데이터는 AX 혹은 AL 레지스터를 이용하여 전송


인터럽트 명령: INT (interrrupt) 다음에 번호를 지정

                     인터럽트 처리 루틴으로부터 원래의 루틴으로 돌아 오려면

                     IRET(interrupt return)을 사용


CPU 제어명령: 주로 8086의 CPU가 수치연산 프로세서 8087과의 사이에서 데이타를 전송한다든지 주변장치로부터 READY 신호가 올 때까지 실행을 정지하고 기다린다든지 하기 위한 명령입니다.

                     WAIT, ESC, LOCK, HLT :  외부 주기

                     NOP: 아무 수행도 하지 않음


그 밖의 명령: 레지스터 혹은 메모리의 내용을 스택영역으로 대피 복귀시키기 위한 PUSH, POP

                     플래그 레지스터를 스택으로 대피 복귀하는 PUSHF, POPF

                     두개의 레지스터 혹은 메모리의 데이터를 교환하는 XCHG

                     한 바이트씩 나열된 데이터의 N 번째의 것을 꺼내는 XLAT

                     

플래그 레지스터를 직접 제어하는 :

                     STC(set carry flag), CLC(clear carry flag),

                     CMC(complement carry flag),

                     STD(set direction flag), CLD(clear direction flag),

                     STI(set interrupt-enable flag)

                     CLI(clear interrupt-enable flag)

                     LAHF(load AH from flags), SAHF(store AH to flags) :

                     플래그 레지스터 하위 8바이트와 AH 레지스터의 데이터를 전송  

                     

                     AAA(ASCII adjust for addition),

                     DAA(decimal adjust for addition),

                     AAS(ASCII adjust for subtract),

                     DAS(decimal adjust for subtract),

                     AAM(ASCII adjust for multiply),

                     AAD(ASCII adjust for division) :

                     플래그 레지스터 하위 8바이트와 AH 레지스터의 데이터를 전송

                     (이상 모두 오퍼랜드를 갖지 않음)

                     LEA(load effective address): 실효번지를 로드

                     LDS(load data segment register),

                     LES(load extra segment register):

                     세그먼트 레지스터를 포함하는 실효번지를 로드함


그렇다면 우리가 올리디버거로 디버그 할때 명령어는 어떻게 생겼냐~?


L1:     MOV     AX,BX   ;comment

+-----+ +----------+ +-------------+ +-------------+ +----------+

|라벨 | |작동 코드 | |제 1 오퍼랜드| |제 2 오퍼랜드| |설명문    |

+-----+ +----------+ +------+------+ +-------+-----+ +----------+




L1:   과 같은 명령은 직접적으로는 기계어 코드로 번역되지 않고, 분기명령 등에서 참조 될 때에 번지의 계산에 사용됩니다.

      이와 같은 명령을 의사 명령이라고 말하고, 어셈블리 프로그램을 작성하는데 없어서는 안되는 것이죠 ^ㅡ^

* 주의 할점은 우리가 올리디버거로 읽을때는, 일본만화를 보는것과 같이 오른쪽에서 왼쪽으로 읽습니다.

설명문 -> 2 오퍼랜드 ㅡ> 1 오퍼랜드 ㅡ> 작동코드.

위의 예를 보면 comment (이건 설명이 아무것도 아니니 무시하고 ㅡㅡ+)  BX를 AX 에 넣어라(MOV)

그럼 이걸 언제 어디에서 넣냐 ? 

당연히 주소문에 있는 주소대로 이겠죠 ?




이 명령어들은 리버싱을 잘 하실려면 필수적으로 외우셔야 됩니다.
제가 외울때는 영어만 있어서 번역하느라 고생했는데 ㅠ.,ㅠ
이것만 잘 외우시고 명령어와 어느정도 친근감이 느껴 지신다면, 크랙은 어려운거 아니면 (공유프로그램 같은 쉬운것들은)
 몇분안에 다 해칠울수 있다고 장담합니다.
(실제로 무섭게 리버싱 빨리하는분이 말씀해주신거니 믿으셔도 될듯)

그럼 무언가를 조금 배워가셨기를 빌며, 좋은하루 되세요. ^ㅡ^/
반응형
IDA Pro는 OllyDbg보다 시각적인 부분과 Symbol 찾는 것 등에 장점이 있다.
하지만, 기능이 많고, 메뉴가 숨어있는 탓에 사용법이 어렵고, 익숙해지기 힘든 점이 있다.
나에게도 여전히 OllyDbg가 익숙하며, IDA는 코드의 흐름을 보거나 Symbol에 대한 정리가 필요할 때 잠깐씩 이용한다.
하지만, 잡스럽게 여러 도구들을 이용하는 것보다, 하나의 도구에 익숙해지려 했다.
그래서 간략히 IDA에 대해 정보를 찾던 중 Hex-Ray라는 좋은 플러그인이 있다길래 공부하는 겸 해서 정리한다.

Hex-Ray는 http://www.hex-rays.com/ 의 프로젝트 페이지를 갖고 있으며,
주요 메뉴얼에 대한 정보는 http://www.hex-rays.com/manual/ 에 나와있다.

Hex-Ray에 대해 짧게 기술을 한다면, De-Compiler이다.
OllyDbg나 IDA Pro는 기본적으로 Dis-Assembler의 속성을 갖고 있다.
그래서, Assembly 코드를 잘 표현하는데에 기능이 치중되어있다.
하지만, 그 정보를 활용해 De-Compiler의 기능을 플러그인으로 구현한 것이 Hex-Ray이다.

Hex-Ray를 이용하면, 우리에게 보다 친숙한 C 코드로 변환된 바이너리를 볼 수 있다.

(아래 : 기본적인 Dis-Assemble된 코드)
사용자 삽입 이미지

위 그림은 프로세스를 숨기기 위해 작성된 DKOM 드라이버 코드를 나타내고 있다.

아래 그림은 위 코드를 F5 단축키를 통해 Psuedo C Code로 변환된 드라이버의 모습을 나타내고 있다.

사용자 삽입 이미지

이를 텍스트로 옮기면 아래와 같다.

NTSTATUS __stdcall DriverEntry(PDRIVER_OBJECT DriverObject, int a2)
{
  NTSTATUS result; // eax@1
  PDRIVER_OBJECT v3; // esi@1
  NTSTATUS v4; // ebx@2
  int v5; // eax@3
  NTSTATUS v6; // eax@2
  PDEVICE_OBJECT DeviceObject; // [sp+14h] [bp-4h]@1
  LSA_UNICODE_STRING DestinationString; // [sp+Ch] [bp-Ch]@1
  LSA_UNICODE_STRING SymbolicLinkName; // [sp+4h] [bp-14h]@1
  DeviceObject = 0;
  RtlInitUnicodeString(&DestinationString, &word_1078A);
  RtlInitUnicodeString(&SymbolicLinkName, &word_107B2);
  v3 = DriverObject;
  result = IoCreateDevice(DriverObject, 0, &DestinationString, 0x22u, 0x100u, 0, &DeviceObject);
  if ( result >= 0 )
  {
    v6 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString);
    v4 = v6;
    if ( v6 >= 0 )
    {
      v3->DriverUnload = (PDRIVER_UNLOAD)DriverUnload;
      gProcessNameOffset = GetProcessNameOffset();
      v5 = FindProcessByName("notepad.exe");
      pHidenProc = v5;
      if ( v5 )
      {
        hHidenProc = v5 + 132;
        HideProcess(v5);
      }
      __asm { mov     eax, cr0 }
      _EAX &= 0xFFFEFFFFu;
      __asm { mov     cr0, eax }
      oldZwQuerySystemInformation = (int)*(&imp__KeServiceDescriptorTable
                                         + *(_DWORD *)((char *)ZwQuerySystemInformation + 1));
      *(&imp__KeServiceDescriptorTable + *(_DWORD *)((char *)ZwQuerySystemInformation + 1)) = NewZwQuerySystemInformation;
      oldZwTerminateProcess = (int)*(&imp__KeServiceDescriptorTable + *(_DWORD *)((char *)ZwTerminateProcess + 1));
      *(&imp__KeServiceDescriptorTable + *(_DWORD *)((char *)ZwTerminateProcess + 1)) = NewZwTerminateProcess;
      __asm { mov     eax, cr0 }
      _EAX |= 0x10000u;
      __asm { mov     cr0, eax }
    }
    result = v4;
  }
  return result;
}

아래는 실제의 드라이버 코드를 나타내고 있다.
보다시피 거의 유사하다는 것을 확인할 수 있다.

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
 NTSTATUS status = 0;
 PDEVICE_OBJECT DevObj = NULL;
 UNICODE_STRING DeviceNameUnicodeString; // 생성될 장치의 이름
 UNICODE_STRING DeviceLinkUnicodeString; // 생성될 장치의 심볼릭 링크
 PEPROCESS pCurProc = NULL, pNotepadProc = NULL;
 UINT i = 0;
 KdPrint(("\n\n>-------------------------------\n\n"));
 KdPrint(("\n\n------------Init Driver---------\n\n"));
 KdPrint(("\n\n--------------------------------\n\n"));
 RtlInitUnicodeString(&DeviceNameUnicodeString, DEVICENAME);
 RtlInitUnicodeString(&DeviceLinkUnicodeString, DEVICESYMBOLICNAME);
 //////////////////////////////////////////////////////////////////////////
 // Device 객체를 생성
 status = IoCreateDevice(DriverObject,
  0,
  &DeviceNameUnicodeString,
  FILE_DEVICE_UNKNOWN,
  FILE_DEVICE_SECURE_OPEN,
  FALSE,
  &DevObj);
 if(!NT_SUCCESS(status)) {
  KdPrint((" -[DriverEntry::IoCreateDevice] Function Fail\n"));
  return status;
 }
 else
  KdPrint((" +[DriverEntry::IoCreateDevice] Function Success\n"));
 //////////////////////////////////////////////////////////////////////////

 //////////////////////////////////////////////////////////////////////////
 // 심볼릭 링크를 생성 - 장치 이름과 Win32 이름 사이의 링크
 status = IoCreateSymbolicLink(&DeviceLinkUnicodeString, &DeviceNameUnicodeString);
 if(!NT_SUCCESS(status)) {
  KdPrint((" -[DriverEntry::IoCreateSymbolicLink] Function Fail\n"));
  return status;
 }
 else
  KdPrint((" +[DriverEntry::IoCreateSymbolicLink] Function Success\n"));
 //////////////////////////////////////////////////////////////////////////

보다시피 Hex-Ray는 Dis-Assemble 된 코드에 대해 훌륭하게 De-Compile된 코드를 제공한다. 이를 활용하면, 실제 바이너리 분석이나 어셈코드 공부에 많은 도움을 얻을 수 있다.

+ Recent posts