반응형

작성 중....................

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
#include <Windows.h>
 
static int v1 = 0;
static int v2 = 0;
 
VOID WINAPI Tls_callback1(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
    if (Reason == DLL_PROCESS_ATTACH)
        v1 = 1;
}
VOID WINAPI Tls_callback2(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
    if (Reason == DLL_PROCESS_ATTACH)
        v2 = 2;
}
 
#pragma comment (linker, "/INCLUDE:__tls_used")
 
/**** Section 1. Start
TLS callback 함수 등록은 Section 1 이나 Section 2 스타일 모두 가능.
 
#pragma comment (linker, "/INCLUDE:_p_tls_callback1")
 
#pragma data_seg(push)
#pragma data_seg(".CRT$XLC")
EXTERN_C PIMAGE_TLS_CALLBACK p_tls_callback1 = Tls_callback1;
#pragma data_seg(".CRT$XLD")
EXTERN_C PIMAGE_TLS_CALLBACK p_tls_callback2 = Tls_callback2;
#pragma data_seg(pop)
 
Section 1. End ****/
 
/**** Section 2 Start ****/
 
#pragma data_seg(push)
#pragma data_seg(".CRT$XLC")
EXTERN_C PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { Tls_callback1, Tls_callback2, 0 };
#pragma data_seg()
#pragma data_seg(pop)
 
/**** Section 2 End ****/
 
int main() {
 
    printf("Test values from tls callbacks are: tls1 = %d, tls2 = %d\n", v1, v2);
 
    return 0;
}
 

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <Windows.h>
 
VOID WINAPI Tls_callback(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
    if (Reason == DLL_PROCESS_ATTACH)
        if (IsDebuggerPresent())
        {
            MessageBoxA(NULL"Debugger present.""Detector", MB_OK);
            exit(-1);
        }
}
 
#pragma comment (linker, "/INCLUDE:__tls_used")
#pragma comment (linker, "/INCLUDE:_p_tls_callback")
 
#pragma data_seg(push)
#pragma data_seg(".CRT$XLC")
EXTERN_C PIMAGE_TLS_CALLBACK p_tls_callback = Tls_callback;
#pragma data_seg(pop)
 
int main() {
 
    printf("No debugger present.");
 
    return 0;
}
 

 

 

 

 

 

 

참고

https://lallouslab.net/2017/05/30/using-cc-tls-callbacks-in-visual-studio-with-your-32-or-64bits-programs/

https://blog.naver.com/stop2y/221201916660

 

 

반응형
Posted by J-sean
:
반응형

x32dbg/x64dbg에서 어셈블리 니모닉 도움말을 사용할 수 있다.

 

수많은 어셈블리 명령에 대한 설명이 없다.

 

설명이 필요한 명령에서 우클릭 - Help on mnemonic을 클릭한다.

 

Log 창에 자세한 설명이 표시된다.

 

전체적으로 간단한 설명을 보고 싶다면 우클릭 - Show mnemonic brief를 클릭한다.

 

 

모든 어셈블리 명령에 대해 간단한 도움말을 표시해 준다.

 

반응형
Posted by J-sean
:
반응형

특정 코드를 레퍼런스하는 명령을 찾아보자.

 

한 화면에 들어오는 가까운 거리에서는 CPU창 왼쪽 화살표로 레퍼런스를 확인할 수 있다.

 

레퍼런스가 멀리 있거나 여러 개 라면 해당 명령(주소)에서 우클릭 - Find references to - Selected Address(es)를 클릭한다.

 

References 창에 레퍼런스가 표시된다.

 

레퍼런스를 좀 더 편하게 확인하고 싶다면 CPU 창에서 우클릭 - Analysis - Analyze module을 클릭한다.

 

 

레퍼런스를 확인하고 싶은 명령에서 우클릭 - xrefs... 를 클릭한다.

 

레퍼런스 창 안의 레퍼런스를 선택하면 그 레퍼런스로 바로 이동할 수 있다. Cancel 버튼을 클릭하면 명령으로 돌아간다.

 

반응형
Posted by J-sean
:
반응형

비주얼 스튜디오로 어셈블리 프로젝트를 시작해 보자.

 

Empty Project를 만든다.

 

프로젝트에 적당한 파일을 add한다. 확장자만 asm으로 지정하면 된다.

 

Solution Explorer - Project Name 우클릭 - Build Dependencies - Build Customizations...

 

masm(.targets, .props)를 선택한다.

 

 

소스파일 우클릭 - Properties

 

Item Type - Microsoft Macro Assembler를 선택한다.

 

32비트 프로그램을 개발한다면 x86을 선택한다.

 

별도의 라이브러리를 사용한다면 아래와 같이 세팅한다.

Irvine.zip
1.30MB

 

Solution Explorer - Project Name 우클릭 - Properties

 

 

사용할 라이브러리의 디렉토리 경로를 입력한다.

 

라이브러리 이름을 입력한다.

 

Microsoft Macro Assembler - General - Include Paths에 라이브러리 경로를 한 번 더 입력한다.

 

소스를 입력한다.

 

 

빌드하고 실행한다.

 

Syntax Highlighter는 AsmDude나 ChASM을 사용한다.

 

ChASM - works with Visual Studio 2022

AsmDude - works with 2015, 2017, 2019

 

ChASM.vsix
0.27MB

 

※ 참고

 

Release 모드에서 SAFESEH 관련 LNK1281, LNK2026 에러가 발생할 수 있다.

 

Microsoft Macro Assembler - Advanced - Use Safe Exception Handlers를 Yes (/safeseh)로 바꾼다.

 

 

작업중인 Sorce.obj 파일의 에러는 해결되었지만 라이브러리 파일의 에러는 해결되지 않았다.

 

Linker - Advanced - Image Has Safe Exception Handlers를 No (/SAFESEH:NO)로 바꾼다.

 

에러가 사라졌다.

 

※ 참고

리스트 파일을 생성해야 한다면 아래와 같이 세팅한다.

 

Microsoft Macro Assembler - Listing File - Assembled Code Listing File - 파일 이름을 지정한다.

 

 

프로젝트를 빌드하면 리스트 파일이 생성된다.

 

반응형
Posted by J-sean
:
반응형

CMOVcc (Conditional Move) 명령어를 사용해 보자.

 

CMOVE - 같으면(ZF=1) 이동한다.

 

CMOVNE - 같지 않으면(ZF=0) 이동한다.

 

eax와 ebx가 같지 않기 때문에 ecx에 eax 값 1이 저장된다.

 

eax와 ebx가 같지 않기 때문에 ecx에 eax 값 1이 저장되지 않는다.

 

반응형
Posted by J-sean
:
반응형

Intel® 64 and IA-32 Architectures Software Developer’s Manual을 확인해 보자.

 

 

RDTSC—Read Time-Stamp Counter

Reads the current value of the processor’s time-stamp counter (a 64-bit MSR) into the EDX:EAX registers. The EDX register is loaded with the high-order 32 bits of the MSR and the EAX register is loaded with the low-order 32 bits. (On processors that support the Intel 64 architecture, the high-order 32 bits of each of RAX and RDX are cleared.) The processor monotonically increments the time-stamp counter MSR every clock cycle and resets it to 0 whenever the processor is reset.

RDTSC 인스트럭션은 프로세서의 time-stamp counter를 EDX:EAX 레지스터로 가져온다. EDX에는 상위 32비트가 저장되고 EAX에는 하위 32비트가 저장된다.

 

EDX, EAX에 저장되는 값을 확인해 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
%include "io64.inc"
 
section .text
global CMAIN
CMAIN:
    rdtsc
 
    PRINT_STRING 'High-order 32 bits of Time Stamp Counter: '
    PRINT_HEX 4, edx
    NEWLINE
    NEWLINE
    
    PRINT_STRING 'Low-order 32 bits of Time Stamp Counter: '
    PRINT_HEX 4, eax
    NEWLINE
    NEWLINE
    
    PRINT_STRING 'Time Stamp Counter: '    
    shl rdx, 32
    xor rdx, rax
    PRINT_HEX 8, rdx
 
    xor rax, rax
   ret
 

 

 

EDX, EAX의 값을 확인한다.

 

EAX 레지스터에 저장된 값을 이용해 1~10까지의 랜덤 넘버를 추출해 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
%include "io64.inc"
 
section .text
global CMAIN
CMAIN:
    rdtsc
    
    ;eax에 저장되는 값을 사용한다.
    PRINT_STRING 'Low-order 32 bits of Time Stamp Counter (dividend): '
    PRINT_HEX 4, eax
    NEWLINE
    NEWLINE
    
    ;2byte 이상 나누기 연산시 div 는 dx, ax를 사용한다.
    ;나누어지는 값을 dx:ax에 나누어 삽입해야 하므로 edx를 0으로 만들고 eax의
    ;값 중 2바이트만 사용한다.
    xor edx, edx
    and eax, 0x0000ffff
    PRINT_STRING 'DX: '
    PRINT_HEX 2, dx
    NEWLINE
    PRINT_STRING 'AX: '
    PRINT_HEX 2, ax
    NEWLINE
    NEWLINE
    
    mov bx, 0xa ;나누는 수를 10으로 설정한다.
    PRINT_STRING 'Divisor: '
    PRINT_HEX 2, bx
    NEWLINE
        
    div bx ;bx(10)로 나눈다. 나머지는 0~9가 나온다.
    PRINT_STRING 'Quotient: '
    PRINT_HEX 2, ax ;몫은 ax에 저장된다.
    NEWLINE
    PRINT_STRING 'Remainder: '
    inc dx
    ;나머지는 dx에 저장된다. 1을 더해서 범위를 1~10으로 맞춘다.
    PRINT_HEX 2, dx
    
    xor rax, rax
   ret
 

 

 

 

Remainder로 1~10의 숫자가 무작위로 추출된다.

 

그런데 실제로 여러번 해 보면 홀수만 나오는 것을 알 수 있다. 내 컴퓨터에서만 그러는건지는 모르겠지만 rdtsc 명령어가 (EAX 레지스터에)짝수만 반환하기 때문이다. (마지막에 1을 더하므로 결국 홀수가 된다)

 

EDX 레지스터의 값을 사용해 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
%include "io64.inc"
 
section .text
global CMAIN
CMAIN:
    rdtsc
    
    ;edx에 저장되는 값을 사용한다.
    PRINT_STRING 'High-order 32 bits of Time Stamp Counter (dividend): '
    PRINT_HEX 4, edx
    NEWLINE
    NEWLINE
    
    ;2byte 이상 나누기 연산시 div 는 dx, ax를 사용한다.
    ;나누어지는 값을 dx:ax에 나누어 삽입해야 하므로 edx의 값을 eax에 저장하고
    ;edx를 0으로 만든다. 그리고 eax의 값 중 2바이트만 사용한다.
    mov eax, edx    
    xor edx, edx
    and eax, 0x0000ffff
    PRINT_STRING 'DX: '
    PRINT_HEX 2, dx
    NEWLINE
    PRINT_STRING 'AX: '
    PRINT_HEX 2, ax
    NEWLINE
    NEWLINE
    
    mov bx, 0xa ;
    PRINT_STRING 'Divisor: '
    PRINT_HEX 2, bx
    NEWLINE
        
    div bx
    PRINT_STRING 'Quotient: '
    PRINT_HEX 2, ax
    NEWLINE
    PRINT_STRING 'Remainder: '
    inc dx
    PRINT_HEX 2, dx
 
    xor rax, rax
   ret
 

 

 

홀수, 짝수 상관없이 1~10의 숫자가 무작위로 추출된다.

하지만 EDX 레지스터의 값은 일반적인 시간의 '초' 단위와 비슷한 간격으로 바뀐다. 프로그램을 빠르게 반복 실행하면 동일한 숫자가 반복되어 나오는걸 알 수 있다. 빠른 반복 추출이 필요하다면 EAX 레지스터의 값 중 하위 2바이트가 아닌 중간 2바이트 숫자를 이용하는 등 다른 방법으로 랜덤 넘버를 추출한다.

 

※ 주의

DIV 연산시 나누는 수가 작아 몫이 너무 크게 되면 ax가 저장할 수 있는 용량(2바이트)을 넘어서게 되고 Program received signal SIGFPE, arithmetic exception 메세지가 나타난다. Floating-Point Exception을 의미하지만 0으로 나누는 연산과 같은 모든 산술 연산 에러를 포함한다.

Program Error Signals

 

SIGFPE 예외 발생시 프로그램이 멈추게 된다. 디버깅해야 메세지를 확인 할 수 있다.

 

반응형
Posted by J-sean
:
반응형

치트엔진에 주소가 표시될 때 모듈 이름과 상대 주소의 연산으로 표시되지 않고 절대 주소로 표시되도록 해 보자.

 

스캔 결과 중 static 주소는 '모듈이름+상대주소' 방식으로 표시된다. 절대 주소로 표시해 보자.

 

스캔 결과 창에서 우클릭 - Preferences 를 클릭한다.

 

'Show static addresses using their static notat' 의 체크 표시를 해제한다.

 

절대 주소로 표시된다.

 

 

Memory Viewer의 주소 표시 방법도 바꿔보자.

 

View - Show module addresses가 체크되어 있다. 체크해제 한다.

 

절대 주소로 표시된다.

 

반응형
Posted by J-sean
:
반응형

x32dbg/x64dbg가 재배치된 PE 파일을 어떻게 표시하는지 알아보자.

 

프로그램을 x86dbg에서 로드하고 CPU창에서 기계어 코드를 보면 빨간 밑줄로 표시된 코드를 볼 수 있다.  이건 어떤 의미일까? 제일 먼저 만나게 되는 00D93691 주소의 A037D900 을 확인해 보자.

 

우선 Symbols 창을 확인해 보자. notepad.exe는 00D90000 주소에 로딩 되었다.

 

Address of Entry Point는 00003689 이다.

 

Base Relocation Table을 확인해 보면 RVA 3691에 PE 재배치 작업이 필요한 하드코딩 주소가 있는걸 확인할 수 있다. 그래서 x86dbg/x96dbg는 00D93691에 빨간 밑줄을 표시한다.

 

 

다른 위치도 확인해 보자. Base Relocation Table에서 RVA 14AF 주소를 발견했다. 이 위치의 기계어 코드에도 밑줄이 표시되어 있을까?

34AF - 최상위 4비트(Type) = 4AF(Offset)

RVA = 1000(RVA of Block) + 4AF = 14AF

Virtual Address = 00D90000(파일 실제 로딩 주소) + 14AF = 00D914AF

 

00D914AF 주소에 빨간 밑줄이 표시되어 있다.

 

반응형
Posted by J-sean
: