치트앤진에서 Hex(16진수)로 표기되는 부분을 Dec(10진수)로 변환한 값을 사용해야 오토핫키에서 메모리 읽기가 된다
메모리 정수값에는 32비트에 속한 포인터와 단일 메모리 주소인 비포인트가 있다. 즉, 포인터의 기본 주소와 비포인터의 메모리 주소가 존재한다.
포인터의 최종주소를 계산하는데 사용되는 다양한 Offset 목록을 확보하는게 관건이다. Offset을 사용할 때 주소 매개 변수는 포인터의 기본 주소와 같아야 한다.
즉, 기본 주소와 오프셋은 정수를 유지하는 메모리 주소를 의미한다.
대상 프로그램이 할당되는 메모리 경로 파악이 필수이며 Offset을 얻으려면 치트엔진의 포인터 스캔이 필수...
확실하진 않지만 ReadMemory, WtiteMemory는 10진수만 읽는 듯 하다...
주소
최고관리자2026-06-24 (수) 20:252개월전
위와 같이 DllCall 함수를 이용하여 api에 접근할 수 있다. 다만 이를 위해서 대상의 PID와 원하는 값의 메모리 주소를 알아야할 필요가 있다.
PID는 AHK 내장의 윈도우 handle값을 반환하는 WinExist() 함수와 윈도우 창의 정보를 겨져올 수 있는 WinGet함수를 이용하여 가져온다.
프로그램에 대한 자동적인 입력은 크게 세 부분으로 나눠볼 수 있다. 1)입력을 만드는 방식과, 2)입력으로 발생하는 메시지를 직접 만드는 방식, 3)외부 하드웨어를 이용한 방식이 있다. 문서에서는 하드웨어를 이용한 방식은 다루지 않을 것이다.
1의 방법은 일반적으로 구현하기 가장 쉬운 방법이다. 특정 프로그램을 구분하지 않고, 단순하게 키보드, 마우스 등의 입력을 발생시킨다. 발생된 입력은 일반적으로 활성화된 창[activated window]에 전해진다. 활성화된 창이란 실행중인 프로세스 중 키보드, 마우스 등의 입력에 대해 대기하고 있는, 가장 foreground process이며, 여러 방법(어플리케이션 실행, Alt+Tab, 작업 표시줄 등의 다른 창 클릭 등)을 이용해 창의 활성화, 비활성화 상태를 바꿀 수 있다.
AHK에서 제공하는 Send 함수는 활성화된 창에 대한 키보드 입력을 만들 수 있으며, SetKeyDelay 함수를 이용하여 입력간의 기본 지연 시간을 설정할 수 있다. MouseClick, MouseMove 함수를 이용하여 마우스 이동, 입력을 하고, SetMouseDelay 함수로 마우스 입력간의 지연시간을 설정할 수 있다. 이러한 함수들을 이용하여 작성한 코드들은 일반적으로 단축키에 동작시키는 함수들을 연결하여 반복 작업이나 정밀 작업을 하는 데에 사용된다.
주소
최고관리자2026-06-24 (수) 20:252개월전
1::
SetBatchLines, -1
CoordMode, Pixel, Screen
CoordMode, Mouse, Screen
x = 8
y = 97
Loop
{
x++
PixelGetColor, cc, x, y
if ( cc <> 0xFFFFFF) {
sx := x
Break
}
}
Loop
{
x++
PixelGetColor, cc, x, y
if ( cc == 0xFFFFFF){
lx := x
Break
}
}
size := lx-sx
Loop
{
x :=sx
Loop
{
PixelGetColor, color, x, y
if ( color <> 0xFFFFFF && color <> tarcolor )
{
MouseClick, L, x, y
sleep, 500
msgbox % "good"
Return
}
if ( x > 430 )
Break
x := x+(size+4)
}
y := y+(size+4)
if ( y > 520 + size)
Break
}
msgbox % "cant"
Return
Trend Micro 2015 : Program 100 문제 풀이의 일부분이다. PixelGetColor 함수를 통해 화면의 픽셀을 읽어 그에 맞추어 MouseClick 함수를 호출, 적절한 픽셀을 클릭한다.
다만 이러한 방식을 사용하게 되면, 발생하는 문제점은 긴 시간 지속적으로 반복 작업을 수행해야하는 경우, 직접적인 키보드, 마우스 입력과 동일하게 진행되기 때문에, PC 한 대의 자원을 모두 사용하거나 작업을 수행할 가상머신을 이용하여야 하기 때문에 자원의 낭비가 심하다. 또한 단순 반복이 아닌 조건에 따라 분기를 수행해야하는 경우, 그래픽에 따라 조건을 확인하는 것이 보통이며, 이러한 작업은 상당히 비효율적으로 수행된다. 따라서 일반적으로 볼 수 있는 자동화 프로그램은 이러한 방식을 사용하지 않는다. 앞서 이야기한 2번의 방식을 사용한다.
주소
최고관리자2026-06-24 (수) 20:262개월전
윈도우는 message-passing model을 사용한다. OS는 어플리케이션 창과 메시지를 주고받아 통신한다. 메시지는 각 특정이벤트에 대해 숫자로 정의되어있다. 메시지를 주고받는 예로, 마우스 왼쪽 마우스 클릭을 들어보면, 사용자가 마우스의 왼쪽 버튼을 누르면 창은 WM_LBUTTONDOWN로 정의된 0x0201의 메시지코드를 전달받아 이에 해당하는 동작을 수행한다. WM_LBUTTONDOWN의 경우는 추가적으로 커서의 x, y 좌표에 대한 정보를 동시에 전달받는다.
메시지를 이용한 방식은 입력만을 만드는 방식과 다르게 어플리케이션 창의 PID, 핸들, 이름 등을 알면 동시에 여러 어플리케이션에 입력을 할 수 있으며, 어플리케이션이 활성화되지 않은 상태에서도 어플리케이션을 동작시킬 수 있고 어플리케이션을 활성화하지 않는다, 또한 상대적으로 빠른 속도로 신뢰성 있는 입력이 가능하다. 단순한 키보드, 마우스의 입력 외에도 메뉴 내의 버튼을 바로 누르는 등의 기능도 제공된다.
다만 이를 이용하는 방식은 입력만을 보내는 것에 비해 복잡한편이다. WinAPI의 PostMessage[링크], SendMessage[링크]함수를 이용해 한번의 키 입력을 예로 들면, 키를 누르고 다시 들어 올리는 각 1회씩 총 2번의 함수 호출과, 키 누르고, 올리는 각각의 메시지의 값, 키들에 해당하는 2개의 파라미터가 기본적으로 필요하며, 메시지가 전달될 창의 핸들, 창의 이름 또는 창의 PID가 필요하다. 입력만을 전달하는 경우, 단순하게 입력할 키만을 파라미터로 하여 호출하면 되는 것과는 대조적이다.
함수는 PostMessage보다 환경에 적합하다고 생각된 SendMessage를 이용할 것이며, 사용할 Msg는 WM_KEYDOWN[링크]과 WM_KEYUP[링크] 두 가지로 각각 0x100, 0x101로 정의되어 있다. 메시지 함수들의 wParam, lParam은 함수에 이용할 Msg의 형태에 따라 적용된다. WM_KEYDOWN, WM_KEYUP의 wParam은 Virtual-Key Code이며 [링크]에서 확인가능하다. lParam은 다음의 표와 같이 그 값을 지정할 수 있다. 자세한 내용은 [링크]에서 확인가능하다.
0-15 : 반복 회수
16-23 : OEM에 따른 Scan Code
24 : 확장형 키 여부
25-28 : 미사용
29 : 컨텍스트 코드
30 : 이전 키의 상태
31 : 변화 여부
또한 메시지 함수들은 메시지가 전달될 창의 핸들을 받아 핸들에 메시지를 전달할 수 있다. 핸들이 없다면 현재 메시지 함수를 호출한 핸들에 전달된다. 다음은 쿼터 뷰 형식을 채용하여 45도 회전된 좌표계를 사용하는 대상의 지정한 x, z 좌표로 이동하게 만드는 함수이다. px, pz는 직전의 좌표를 구하는 함수를 이용하여 구할 수 있다.
이동에 상하좌우는 각각 I, K, J, L 키를 이용하며, 코드를 실행시키면 창 활성화와 관계없이 지정한 좌표까지 이동한다.
핸들을 찾는 방법은 다음 간단하게 추가할 예정이다.
주소
최고관리자2026-06-24 (수) 20:262개월전
#Include classMemory.ahk
;아래 구절은 필수가 아님 - 클래스를 올바르게 복사했는지 확인할 뿐
if (_ClassMemory.__Class != "_ClassMemory")
msgbox class memory not correctly installed. Or the (global class) variable "_ClassMemory" has been overwritten
;실행대상 프로그램 메모리를 읽을 객체를 만듬
;실행대상의 프로세스가 실행 중이여야만 됨
;만약 프로세스가 닫혔거나 다시 시작되었을 때 아래 구문을 다시금 호출해야한다.
실행대상 := new _ClassMemory("ahk_exe GOM.EXE", "", hProcessCopy)
;아래 구절은 필수가 아님 - 객체생성 실패에 대한 이유를 얻을 수 있을 뿐
if !isObject(실행대상)
{
msgbox failed to open a handle
if (hProcessCopy = 0)
msgbox The program isn't running (not found) or you passed an incorrect program identifier parameter.
else if (hProcessCopy = "")
msgbox OpenProcess failed. If the target process has admin rights, then the script also needs to be ran as admin. Consult A_LastError for more information.
ExitApp
}
;아래 구문은 필수가 아님 - 기본 주소를 더 쉽게 읽을 수 있도록할 뿐
SetFormat, integerfast, H
;포인터가 가르키는 문자열 읽기
msgbox Your CE pointer screenshot didnt show the complete base address of the pointer. Im just guessing its the same as the previous one.
;두 번째 매개변수는 읽을 바이트 수를 나타낸다.
;만약 두 번째 매개변수가 0 혹은 문자열이 null(CE메모리뷰의 끝 문자열이 00인 경우)로 귀결되면 전체 문자열을 자동으로 읽어들인다.
;이러한 경우 읽어오는 문자열이 유니코드가 아니기에 UTF-8을 사용한다.
msgbox % 실행대상.readString(실행대상.BaseAddress + 0x8EC28C, 0, "UTF-8", 0xC, 0x24, 0x0)
F1::
WinGet, 프로세스패치, ProcessPath, A
WinGet, 프로세스아이디, PID, A
WinGet, 실행명, ProcessName, A
WinGet, 활성창HWAN, ID, A
WinGetTitle, 창이름, ahk_id %활성창HWAN%
WinGetClass, 클래스, ahk_id %활성창HWAN%
msgbox %프로세스패치%`n[ %프로세스아이디% ] %실행명%(%활성창HWAN%)`n%창이름%`n%클래스%
return
주소
최고관리자2026-06-24 (수) 20:272개월전
"eax가 가리키는 주소에 있는 값을 edx로 복사" 는 틀린말입니다.
eax레지스터에는 그냥 값이 들어있고요 edx에 복사를 할 주소값이 있습니다.
즉, "eax의 값을 edx가 가르키는 주소로 복사" 가 맞는 말이겠죠?
'edx = eax' X 가 아니고 'edx가 가르키는 값 = eax' 입니다.
치트엔진 강의 잘 보고 갑니다. 정말 유용하고 깔끔하네요. 감사합니다^^
[EAX*2+EDX+00000310] eax=4C and edx=00801234.
이러한 경우에 EDX는 포인터가 가진 값이 되고, EAX*2+00000310이 오프셋이 되며,
그러므로 당신이 입력해야하는 오프셋은 2*4C+00000310=3A8 가 될겁니다.
(이 모든것은 16진수값이며, 계산을 위해 윈도우 cal.exe의 공학용 모드를 사용하세요)
혹은 튜토리얼 프로그램 재실행 시, 조금 더 간단한 식이 나올수도 있습니다.
주소
최고관리자2026-06-24 (수) 20:272개월전
컴퓨터 과학에서 배열이나 자료 구조 오브젝트 내의 오프셋(offset)은 일반적으로 동일 오브젝트 안에서 오브젝트 처음부터 주어진 요소나 지점까지의 변위차를 나타내는 정수형이다.
이를테면, 문자 A의 배열이 abcdef를 포함한다면 'c' 문자는 A 시작점에서 2의 오프셋을 지닌다고 할 수 있다.
어셈블리어와 같은 저급 프로그래밍 언어에서 오프셋은 상대 주소(relative address)로 부른다.