Skip to content

Instantly share code, notes, and snippets.

@zbroyar
Last active December 24, 2015 00:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zbroyar/6720528 to your computer and use it in GitHub Desktop.
Save zbroyar/6720528 to your computer and use it in GitHub Desktop.
Пошук та модифікація значень у адресному просторі процесів OS X.В оригіналі призначено для хаку ресурсів у грі "XCOM: Enemy Unknown".
(* ocamlfind ocamlopt -o scan -package unix,pcre scan.ml -linkpkg
Якщо знайти адресу кількості трупів сектоїдів, то забити склад
ніштяками можна, наприклад, так:
let addr = $sectoids
and pid = <XCOM pid>
and ch = open_out "cmd.gdb" in
for i = 0 to 35 do
Printf.fprintf ch "set {int}(0x%X + 4*%d) = 99999\n" addr i
done;
close_out ch;
sudo gdb --batch --command=cmd.dbg -p $pid 2>/dev/null
Див.: http://blog.mykola.org/post/62362762627/xcom-enemy-unknown
*)
open Printf
(*------------------------------------------------------------------------------
* Модулі та типи
-----------------------------------------------------------------------------*)
module S = Set.Make(struct type t = int let compare = compare end)
(*------------------------------------------------------------------------------
* Допоміжні функи
-----------------------------------------------------------------------------*)
let ($) f x = f x
let (%) f g = fun x -> f (g x)
let rec fold_channel_lines f r ch =
let s = try Some (input_line ch) with End_of_file -> None in
match s with
Some s ->
let r =
try f r s
with Not_found -> printf "Invalid line: %s\n%!" s; r in
fold_channel_lines f r ch
| None -> close_in ch; r
(*------------------------------------------------------------------------------
* Бізнес-логіка :-]
-----------------------------------------------------------------------------*)
let find_addresses pid sections value =
let fname = sprintf "tmp.gdb.%d" pid in
let cmd = sprintf "gdb --batch --command=%s -p %d" fname pid
and ch = open_out fname in
List.iter (fun (s,e) -> fprintf ch "find /w 0x%x, 0x%x, %d\n" s e value) sections;
close_out ch;
let rex = Pcre.regexp "^(0x[^[:space:]]+)$"
and ch = Unix.open_process_in cmd in
let set = fold_channel_lines
(fun set str ->
try
let subst = Pcre.exec ~rex str in
let addr = int_of_string % Pcre.get_substring subst $ 1 in
S.add addr set
with Not_found -> set
) S.empty ch in
ignore % Unix.system % sprintf "rm %s" $ fname; set
let modify pid addr value =
let cmd = sprintf "gdb --batch -ex \"set {int}0x%x = %d\" -p %d 2>/dev/null"
addr value pid in
ignore % Unix.system $ cmd
let rec loop ?(found = false) pid sections addresses =
printf "Нове значення? ";
let new_addresses = find_addresses pid sections (read_int()) in
let res = S.inter addresses new_addresses in
let count = S.cardinal res in
printf "Адрес: %d\n%!" count;
match count, found with
| 1,false ->
printf "Знайдено адресу: 0x%X\nКонтрольна ітерація.\n%!"
(List.hd % S.elements $ res);
loop ~found:true pid sections res
| 1, true ->
printf "Підтверджено! Модифікуємо? ";
begin
match read_line () with
| "yes" | "Yes" | "YES" | "так" | "Так" | "ТАК" ->
printf "Скільки ставимо? ";
modify pid
(List.hd % S.elements $ res)
(read_int ())
| _ -> printf "Ну добре. До побачення"
end
| 0, _ -> printf "Облом. Схоже, метод не працює...\n%!"
| _ -> loop pid sections res
(*------------------------------------------------------------------------------
* Головна частина
-----------------------------------------------------------------------------*)
let pid = int_of_string Sys.argv.(1)
let sections =
let s2i s = Scanf.sscanf s "%16x" (fun x -> x) in
let sections_command = sprintf "vmmap %d" pid in
let ch = Unix.open_process_in sections_command
and rex = Pcre.regexp "^.* ([[:xdigit:]]+)-([[:xdigit:]]+) .*$" in
let res = fold_channel_lines
(fun res str ->
(*printf "%s ... " str;*)
try
let subst = Pcre.exec ~rex str in
let r_start = s2i % Pcre.get_substring subst $ 1
and r_end = s2i % Pcre.get_substring subst $ 2 in
(*printf "0x%X -> 0x%X ... OK\n%!" r_start r_end;*)
(r_start, r_end) :: res
with Not_found -> (*printf "ignored\n%!";*) res
) [] $ ch in
List.sort compare res
let initial_addresses =
printf "Cекцій: %d\n%!" % List.length $ sections;
printf "Початкове значення? ";
find_addresses pid sections (read_int ())
let _ =
printf "Адрес: %d\n%!" (S.cardinal initial_addresses);
loop pid sections initial_addresses
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment