Post by Flipeador » 25 Jun 2018, 15:21
Bien, mira, he logrado hacer que funcione en
Notepad++ (buscar una cadena), pero para entender bien el código necesitas tener conocimientos sobre programación, especialmente sobre DllCall, si no lo tienes todo esto puede resultar en una perdida de tiempo, ya que para lograr que funcione puede requerir varias pruebas que incluyen la modificación del código AHK.
Primero que nada, debemos aclarar algunas cosas:
- Para el correcto funcionamiento, debes ejecutar la versión de AHK correcta dependiendo de los bits del proceso. Por ejemplo, si el proceso es de 64-Bit debes utilizar
AutoHotkeyU64.exe.
- AutoHotkey no sirve para esto, debido a que al ser un lenguaje interpretado las operaciones (que son muchas) resultan muy lentas. Lo mejor es utilizar un lenguaje compilado, como C++. Esto también depende de tu PC.
- La codificación de la cadena a buscar debe coincidir con la codificación de la cadena en el programa.
- Si la memoria en donde reside la cadena esta protegida, las cosas se complican aún más, necesitamos añadir más DllCalls.
- Puede que tengas que ejecutar el Script como Administrador.
Primero, vamos hacer una prueba. El ejemplo que te pongo a continuación es para
Notepad++. Si quieres probar, debes ejecutar
Notepad++ y escribir la cadena
SomeDataToFind (codificación ANSI:
Barra de menu\Formato\Convertir en ANSI). Luego al ejecutar el Script te devuelve la dirección de memoria donde empieza la cadena.
Nota: El script es únicamente para AHKv2. Puedes descargarlo desde el enlace en mi firma. Puedes descargar Notepad++ de aquí.
Code: Select all
ProcessID := ProcessExist("notepad++.exe") ; aquí recuperamos el identificador del proceso
String := "SomeDataToFind" ; la cadena a buscar
StrPutVar(String, Data, Size) ; convertimos la cadena a UTF-8
Addr := GetAddressOfData(ProcessID, &Data, Size-1) ; pasamos la dirección de memoria de la cadena UTF-8 y el tamaño de esta (bytes).
MsgBox Addr ; muestra la dirección de memoria del inicio de la cadena
; ------------------------------------------
StrPutVar(String, ByRef Buffer, ByRef Size := "", Encoding := "UTF-8")
{
VarSetCapacity(Buffer, (Size := StrPut(String, Encoding) - VarSetCapacity(Buffer, 0)*0) * ((Encoding = "UTF-16") + 1))
Return IsByRef(Size) ? StrPut(String, &Buffer, Size, Encoding) * 0 + &Buffer : StrPut(String, &Buffer, Size, Encoding)
} ; AutoHotkey Documentation
; https://www.codeproject.com/Articles/716227/Csharp-How-to-Scan-a-Process-Memory
GetAddressOfData(ProcessID, Data, Size)
{
; OpenProcess function
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320(v=vs.85).aspx
; PROCESS_VM_READ = 0x0010 | PROCESS_QUERY_INFORMATION = 0x0400
Local hProcess := DllCall("Kernel32.dll\OpenProcess", "UInt", 0x0010|0x0400, "Int", FALSE, "UInt", ProcessID, "Ptr")
If (!hProcess)
Return FALSE
; SYSTEM_INFO structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx
Local SYSTEM_INFO := ""
VarSetCapacity(SYSTEM_INFO, A_PtrSize == 4 ? 36 : 48)
; GetSystemInfo function
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms724381(v=vs.85).aspx
DllCall("Kernel32.dll\GetSystemInfo", "UPtr", &SYSTEM_INFO)
Local Address := NumGet(&SYSTEM_INFO + 8) ; LPVOID lpMinimumApplicationAddress (the lowest memory address accessible to applications and DLLs)
, MaximumApplicationAddress := NumGet(&SYSTEM_INFO + 8 + A_PtrSize) ; LPVOID lpMaximumApplicationAddress (the highest memory address accessible to applications and DLLs)
; MEMORY_BASIC_INFORMATION structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366775(v=vs.85).aspx
Local sizeof_MEMORY_BASIC_INFORMATION := A_PtrSize == 4 ? 28 : 48
VarSetCapacity(MEMORY_BASIC_INFORMATION, sizeof_MEMORY_BASIC_INFORMATION)
Local RegionSize := 0, State := 0, Protect := 0
While (Address < MaximumApplicationAddress)
{
; VirtualQueryEx function
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366907(v=vs.85).aspx
If (DllCall("Kernel32.dll\VirtualQueryEx", "Ptr", hProcess, "UPtr", Address, "UPtr", &MEMORY_BASIC_INFORMATION, "UPtr", sizeof_MEMORY_BASIC_INFORMATION, "UPtr") == sizeof_MEMORY_BASIC_INFORMATION)
{
Address := NumGet(&MEMORY_BASIC_INFORMATION) ; PVOID BaseAddress (base address of the region of pages)
RegionSize := NumGet(&MEMORY_BASIC_INFORMATION + 3*A_PtrSize) ; SIZE_T RegionSize (size of the region beginning at the base address in which all pages have identical attributes)
State := NumGet(&MEMORY_BASIC_INFORMATION + 4*A_PtrSize, "UInt") ; DWORD State (the state of the pages in the region)
Protect := NumGet(&MEMORY_BASIC_INFORMATION + 4*A_PtrSize + 4, "UInt") ; DWORD Protect (access protection of the pages in the region)
If (State == 0x1000 && Protect == 0x04) ; MEM_COMMIT = 0x1000 | PAGE_READWRITE = 0x04
{
Local Buffer := ""
VarSetCapacity(Buffer, RegionSize) ; out of memory --> use AHKU64 for 64-Bit processes
; ReadProcessMemory function
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms680553(v=vs.85).aspx
Local BytesRead := 0
If (DllCall("Kernel32.dll\ReadProcessMemory", "Ptr", hProcess, "UPtr", Address, "UPtr", &Buffer, "UPtr", RegionSize, "UPtrP", BytesRead))
{
Loop (RegionSize-Size)
{
; https://msdn.microsoft.com/es-es/library/zyaebf12.aspx
If (!DllCall("msvcrt.dll\memcmp", "UPtr", Data, "UPtr", &Buffer+A_Index, "UPtr", Size, "CDecl"))
{
DllCall("Kernel32.dll\CloseHandle", "Ptr", hProcess)
Return Address + A_Index
}
}
}
}
Address += RegionSize
}
}
DllCall("Kernel32.dll\CloseHandle", "Ptr", hProcess)
Return FALSE
}
Para probar en tu juego, cambia el nombre del proceso y la cadena a buscar.
Bien, mira, he logrado hacer que funcione en [c]Notepad++[/c] (buscar una cadena), pero para entender bien el código necesitas tener conocimientos sobre programación, especialmente sobre DllCall, si no lo tienes todo esto puede resultar en una perdida de tiempo, ya que para lograr que funcione puede requerir varias pruebas que incluyen la modificación del código AHK.
Primero que nada, debemos aclarar algunas cosas:
[list][*]Para el correcto funcionamiento, debes ejecutar la versión de AHK correcta dependiendo de los bits del proceso. Por ejemplo, si el proceso es de 64-Bit debes utilizar
[c]AutoHotkeyU64.exe[/c].
[*]AutoHotkey no sirve para esto, debido a que al ser un lenguaje interpretado las operaciones (que son muchas) resultan muy lentas. Lo mejor es utilizar un lenguaje compilado, como [c]C++[/c]. Esto también depende de tu PC.
[*]La codificación de la cadena a buscar debe coincidir con la codificación de la cadena en el programa.
[*]Si la memoria en donde reside la cadena esta protegida, las cosas se complican aún más, necesitamos añadir más DllCalls.
[*]Puede que tengas que ejecutar el Script como Administrador.[/list]
Primero, vamos hacer una prueba. El ejemplo que te pongo a continuación es para [c]Notepad++[/c]. Si quieres probar, debes ejecutar [c]Notepad++[/c] y escribir la cadena [c]SomeDataToFind[/c] (codificación ANSI: [c]Barra de menu\Formato\Convertir en ANSI[/c]). Luego al ejecutar el Script te devuelve la dirección de memoria donde empieza la cadena.
[color=#FF0000]Nota: El script es únicamente para AHKv2. Puedes descargarlo desde el enlace en mi firma. Puedes descargar [c]Notepad++[/c] de [url=https://notepad-plus-plus.org/]aquí[/url].[/color]
[code=autohotkey file=Untitled.ahk]ProcessID := ProcessExist("notepad++.exe") ; aquí recuperamos el identificador del proceso
String := "SomeDataToFind" ; la cadena a buscar
StrPutVar(String, Data, Size) ; convertimos la cadena a UTF-8
Addr := GetAddressOfData(ProcessID, &Data, Size-1) ; pasamos la dirección de memoria de la cadena UTF-8 y el tamaño de esta (bytes).
MsgBox Addr ; muestra la dirección de memoria del inicio de la cadena
; ------------------------------------------
StrPutVar(String, ByRef Buffer, ByRef Size := "", Encoding := "UTF-8")
{
VarSetCapacity(Buffer, (Size := StrPut(String, Encoding) - VarSetCapacity(Buffer, 0)*0) * ((Encoding = "UTF-16") + 1))
Return IsByRef(Size) ? StrPut(String, &Buffer, Size, Encoding) * 0 + &Buffer : StrPut(String, &Buffer, Size, Encoding)
} ; AutoHotkey Documentation
; https://www.codeproject.com/Articles/716227/Csharp-How-to-Scan-a-Process-Memory
GetAddressOfData(ProcessID, Data, Size)
{
; OpenProcess function
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320(v=vs.85).aspx
; PROCESS_VM_READ = 0x0010 | PROCESS_QUERY_INFORMATION = 0x0400
Local hProcess := DllCall("Kernel32.dll\OpenProcess", "UInt", 0x0010|0x0400, "Int", FALSE, "UInt", ProcessID, "Ptr")
If (!hProcess)
Return FALSE
; SYSTEM_INFO structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx
Local SYSTEM_INFO := ""
VarSetCapacity(SYSTEM_INFO, A_PtrSize == 4 ? 36 : 48)
; GetSystemInfo function
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms724381(v=vs.85).aspx
DllCall("Kernel32.dll\GetSystemInfo", "UPtr", &SYSTEM_INFO)
Local Address := NumGet(&SYSTEM_INFO + 8) ; LPVOID lpMinimumApplicationAddress (the lowest memory address accessible to applications and DLLs)
, MaximumApplicationAddress := NumGet(&SYSTEM_INFO + 8 + A_PtrSize) ; LPVOID lpMaximumApplicationAddress (the highest memory address accessible to applications and DLLs)
; MEMORY_BASIC_INFORMATION structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366775(v=vs.85).aspx
Local sizeof_MEMORY_BASIC_INFORMATION := A_PtrSize == 4 ? 28 : 48
VarSetCapacity(MEMORY_BASIC_INFORMATION, sizeof_MEMORY_BASIC_INFORMATION)
Local RegionSize := 0, State := 0, Protect := 0
While (Address < MaximumApplicationAddress)
{
; VirtualQueryEx function
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa366907(v=vs.85).aspx
If (DllCall("Kernel32.dll\VirtualQueryEx", "Ptr", hProcess, "UPtr", Address, "UPtr", &MEMORY_BASIC_INFORMATION, "UPtr", sizeof_MEMORY_BASIC_INFORMATION, "UPtr") == sizeof_MEMORY_BASIC_INFORMATION)
{
Address := NumGet(&MEMORY_BASIC_INFORMATION) ; PVOID BaseAddress (base address of the region of pages)
RegionSize := NumGet(&MEMORY_BASIC_INFORMATION + 3*A_PtrSize) ; SIZE_T RegionSize (size of the region beginning at the base address in which all pages have identical attributes)
State := NumGet(&MEMORY_BASIC_INFORMATION + 4*A_PtrSize, "UInt") ; DWORD State (the state of the pages in the region)
Protect := NumGet(&MEMORY_BASIC_INFORMATION + 4*A_PtrSize + 4, "UInt") ; DWORD Protect (access protection of the pages in the region)
If (State == 0x1000 && Protect == 0x04) ; MEM_COMMIT = 0x1000 | PAGE_READWRITE = 0x04
{
Local Buffer := ""
VarSetCapacity(Buffer, RegionSize) ; out of memory --> use AHKU64 for 64-Bit processes
; ReadProcessMemory function
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms680553(v=vs.85).aspx
Local BytesRead := 0
If (DllCall("Kernel32.dll\ReadProcessMemory", "Ptr", hProcess, "UPtr", Address, "UPtr", &Buffer, "UPtr", RegionSize, "UPtrP", BytesRead))
{
Loop (RegionSize-Size)
{
; https://msdn.microsoft.com/es-es/library/zyaebf12.aspx
If (!DllCall("msvcrt.dll\memcmp", "UPtr", Data, "UPtr", &Buffer+A_Index, "UPtr", Size, "CDecl"))
{
DllCall("Kernel32.dll\CloseHandle", "Ptr", hProcess)
Return Address + A_Index
}
}
}
}
Address += RegionSize
}
}
DllCall("Kernel32.dll\CloseHandle", "Ptr", hProcess)
Return FALSE
}[/code]
Para probar en tu juego, cambia el nombre del proceso y la cadena a buscar.