특정 게임이나 프로그램의 메모리를 수정하거나 특정 동작을 트리거하는 Assembly 스크립트를 분석해보자.
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(Point,800)
registersymbol(Point)
Point:
DB 00 00 00 00 00 00 00 00 00
alloc(MovePoint,500)
registersymbol(MovePoint)
Label(Point2)
Label(Point3)
Label(TerAMM)
Label(SetPoint)
registersymbol(SetPoint)
0040FB1C:
JMP MovePoint
MovePoint:
pushad
cmp [Point],0
JE TerAMM
mov ebx,[NPCMSGFIT]
cmp ebx,01
JE TerAMM // Attack Motion On
mov eax,[0058DAD4]
mov eax,[eax+C]
cmp eax,02
JE TerAMM
cmp [SetPoint],0
JNE Point2
lea eax,[Point]
mov [SetPoint],eax
Point2:
mov eax,[SetPoint]
mov ebx,[eax]
mov ecx,[eax+4]
imul ebx,ecx
push ebx
mov eax,[0058DAD4]
mov ebx,[eax+10]
mov ecx,[eax+14]
imul ebx,ecx
pop eax
cmp eax,ebx
jne Point3
add [SetPoint],10
mov eax,[SetPoint]
cmp [eax],0
JNE Point3
lea eax,[Point]
mov [SetPoint],eax
Point3:
lea eax,[SetPoint]
mov eax,[eax]
mov ebx,[0058DAD4]
push 01
push eax
call 004CA9A1
mov esi,[0058DAD4]
call 004CB4C5
TerAMM:
popad
mov ecx,[ebp+0C]
sub ecx,eax
JMP 0040FB27
SetPoint:
DB 00 00 00 00 00 00 00 00
[DISABLE]
0040FB1C:
mov ecx,[ebp+0C]
sub ecx,eax
[ENABLE] 블록 (기능 활성화 부분)
이 부분은 메모리 값을 수정하거나 특정 동작을 활성화하는 데 사용됩니다. 주석을 달아 놓은 대로 [DISABLE]까지 코드가 실행됩니다.
- alloc(Point,800)
Point라는 이름으로 800바이트를 할당합니다. 이 메모리 공간은 나중에 값들을 저장하기 위해 사용됩니다.
alloc(변수명, Byte 크기) : 특정 명칭의 메모리 공간 할당
- registersymbol(Point)
Point라는 심볼(기호)을 메모리 주소에 연결합니다. 이를 통해 코드에서 Point라는 이름을 참조할 수 있게 됩니다.
registersymbol(변수명) : alloc으로 생성한 변수를 메모리 주소에 연결, 코드에서 변수 참조가 가능해짐
- Point: DB 00 00 00 00 00 00 00 00 00
Point가 시작되는 주소에 9바이트의 00 값을 할당합니다. 이는 메모리 공간을 0으로 초기화하는 역할을 합니다.
"변수명: DB xx xx xx xx ..." : 변수에 해당하는 주소값에 특정 Bytes 값을 할당
- alloc(MovePoint,500)
MovePoint라는 이름으로 500바이트의 메모리 공간을 할당합니다. 이 메모리 공간은 나중에 코드에서 사용될 것입니다. - registersymbol(MovePoint)
MovePoint 심볼을 메모리 주소에 연결합니다. 이를 통해 MovePoint를 코드에서 사용할 수 있습니다. - Label(Point2), Label(Point3), Label(TerAMM), Label(SetPoint)
Point2, Point3, TerAMM, SetPoint라는 라벨을 생성합니다. 라벨은 코드 내에서 특정 위치로 점프하는 데 사용됩니다.
Label(Label명) : 코드 내에서 특정 위치로 점프하는데 사용됨
- 0040FB1C: JMP MovePoint
0040FB1C 주소에 있는 코드를 MovePoint로 점프합니다. 이 코드가 실행되면 MovePoint의 코드로 이동합니다.
"메모리주소값(4Bytes): JMP <Label명>" : 해당 메모리 주소에 있는 코드를 Label로 점프, 즉 해당 메모리의 코드가 실행되면 Label에 해당하는 코드로 이동
MovePoint 코드 (주요 로직)
MovePoint: pushad
- pushad 명령어는 32비트 레지스터를 스택에 푸시하여 나중에 복원할 수 있도록 합니다.
pushad 명령어 : 32비트(4byte) 레지스터를 Stack에 Push하여 나중에 복원할 수 있도록 하는 명령어
cmp [Point],0 JE TerAMM
- Point의 값이 0이면 TerAMM 라벨로 점프합니다.
cmp [변수명],값 JE <Label> : 변수명의 값과 값을 비교(CoMPare)하여 같으면(Jump Equal) 다음 Label 위치로 이동한다.
mov ebx,[NPCMSGFIT] cmp ebx,01 JE TerAMM // Attack Motion On
- NPCMSGFIT의 값을 ebx 레지스터에 복사하고, 그 값이 1이면 TerAMM 라벨로 점프합니다. (아마도 공격 모션이 켜졌을 때의 체크로 보입니다.)
mov ebx,[변수명] : 뒤의 있는 변수의 값을 ebx 레지스터에 데이터를 복사한다.
cmp ebx,값 JE <Label> : ebx 레지스터의 값과 값을 비교하여 같으면 Label 위치로 이동한다.
mov eax,[0058DAD4] mov eax,[eax+C] cmp eax,02 JE TerAMM
- 0058DAD4 주소의 값을 가져오고, 그 값을 eax 레지스터에 로드한 뒤 eax + C 주소의 값을 비교하여, 값이 2이면 TerAMM 라벨로 점프합니다.
cmp [SetPoint],0 JNE Point2
- SetPoint 값이 0이 아니면 Point2로 점프합니다. 0이라면 아래 코드가 실행됩니다.
cmp [변수명 or 메모리 주소명], 값 JNE <Label명> : 변수에 해당하는 값을 비교하여 같지 않으면(Jump Not Equal) 해당 Label 위치로 이동한다.
lea eax,[Point] mov [SetPoint],eax
- Point의 주소를 SetPoint에 저장합니다.
lea eax, [변수명] : 변수에 해당하는 값이 아닌! 주소값을 eax 레지스터에 복사한다.
LEA는 MOV와 다르게 단순하다.
MOV는 값을 가져오는 것이라면 LEA는 주소를 가져온다
Point2: mov eax,[SetPoint] mov ebx,[eax] mov ecx,[eax+4] imul ebx,ecx push ebx mov eax,[0058DAD4] mov ebx,[eax+10] mov ecx,[eax+14] imul ebx,ecx pop eax
- SetPoint 주소에서 ebx와 ecx 값을 가져와서 곱하고, 또 다른 메모리 주소에서 값을 가져와서 비교합니다.
imul ebx,ecx push ebx : ebx레지스터의 값과 ecx 레지스터의 값을 MULtiply하고, ebx 레지스터에 push를 해둔다?
imul ebx,ecx : 두 레지스터의 값을 곱해서, eax 레지스터에 pop한다?
cmp eax,ebx jne Point3
- eax와 ebx의 값이 다르면 Point3로 점프합니다.
add [SetPoint],10
- SetPoint 값을 10만큼 증가시킵니다.
add [변수명], 값 : 변수에 해당하는 값에 값을 더한다.
mov eax,[SetPoint] cmp [eax],0 JNE Point3
- SetPoint 주소에서 값을 가져와 0이 아닌지 확인하고, 0이 아니면 Point3로 점프합니다.
lea eax,[Point] mov [SetPoint],eax
- Point 주소를 다시 SetPoint에 저장합니다.
Point3: lea eax,[SetPoint] mov eax,[eax] mov ebx,[0058DAD4] push 01 push eax call 004CA9A1
- SetPoint의 값을 eax에 로드하고, 특정 함수(주소 004CA9A1)를 호출합니다. 이 함수는 메모리 값을 수정하거나 특정 작업을 수행하는 코드일 가능성이 큽니다.
call <4byte 주소값> : 특정 주소(함수)를 호출합니다.
call 은 스택에 돌아올 주소를 넣는다. 그리고 ret과 같이 쓰이는데, ret은 스택에 돌아올 주소로 가며 스택 pop을 해준다.
jmp는 해당 명령어 주소로 이동한다.
mov esi,[0058DAD4] call 004CB4C5
- 또 다른 함수(주소 004CB4C5)를 호출합니다.
TerAMM 라벨 (리셋 또는 종료 부분)
TerAMM: popad mov ecx,[ebp+0C] sub ecx,eax JMP 0040FB27
- popad는 이전에 푸시된 레지스터 값을 복원합니다.
- ebp+0C에서 ecx 값을 가져와서 eax를 빼고, 특정 주소로 점프합니다.
popad : 이전에 Push해 놓은 레지스터의 값을 복원합니다.
sub ecx, eax : 앞에 있는 값을 가져와서 뒤의 있는 값을 뺀다.
JMP <주소값> : 특정 주소로 이동한다.
SetPoint 메모리 (초기화)
SetPoint: DB 00 00 00 00 00 00 00 00
- SetPoint라는 메모리 영역에 8바이트의 0 값을 할당합니다. 이 값은 코드에서 초기화되어 사용됩니다.
[DISABLE] 블록 (기능 비활성화 부분)
[DISABLE] 0040FB1C: mov ecx,[ebp+0C] sub ecx,eax
- [DISABLE] 블록에서는 0040FB1C 주소에서 실행되던 코드를 원래의 코드로 되돌립니다. mov ecx,[ebp+0C]와 sub ecx,eax 코드가 원래의 동작을 수행하도록 되돌립니다.
<주소값>: 명령어.. : 해당 주소에서 실행되던 코드를 원래의 코드로 되돌립니다.(로직을 직접 구현해야함)
결론
이 코드는 특정 메모리 주소를 수정하고, 조건에 따라 여러 가지 동작을 실행하는 로직을 포함하고 있습니다. 주로 공격 모션을 제어하거나, 특정 NPC의 상태를 점검하는 작업을 수행하는 것 같습니다. 특히 SetPoint, Point, MovePoint와 같은 메모리 공간을 조작하여 특정 동작을 변경하는 부분이 핵심입니다.
이 코드는 Cheat Engine과 같은 메모리 수정 툴에서 자주 사용되는 형태로, 게임이나 프로그램에서 특정 동작을 트리거하거나 값을 수정하여 게임 플레이를 변경하는 데 활용될 수 있습니다.
최근댓글