dfhack/tools/playground/hexsearch2.h

219 lines
8.8 KiB
C

/*
* Author: Silas Dunsmore aka 0x517A5D vim:ts=4:sw=4
*
* Released under the MIT X11 license; feel free to use some or all of this
* code, as long as you include the copyright and license statement (below)
* in all copies of the source code. In fact, I truly encourage reuse.
*
* If you do use large portions of this code, I suggest but do not require
* that you keep this code in a seperate file (such as this hexsearch.h file)
* so that it is clear that the terms of the license do not also apply to
* your code.
*
* Should you make fundamental changes, or bugfixes, to this code, I would
* appreciate it if you would give me a copy of your changes.
*
*
* Copyright (C) 2007-2008 Silas Dunsmore
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* See also: http://www.opensource.org/licenses/mit-license.php
* and http://en.wikipedia.org/wiki/MIT_License
*/
#ifndef HEXSEARCH_H
#define HEXSEARCH_H
#ifdef __cplusplus
extern "C"
{
#endif
extern DWORD df_memory_base, df_memory_start, df_memory_end;
extern HANDLE df_h_process, df_h_thread;
extern DWORD df_pid, df_main_win_tid;
extern DWORD here[16];
extern DWORD target[16];
// ============================================================================
// export these in case you need to work with them directly.
//extern HANDLE df_h_process, df_h_thread;
//extern DWORD df_pid, df_main_win_tid;
extern char *errormessage;
// ============================================================================
// send info to KERNEL32:OutputDebugString(), useful for non-console programs.
// (you can watch this with SysInternals' DebugView.)
// http://www.microsoft.com/technet/sysinternals/Miscellaneous/DebugView.mspx
void d_printf(const char *format, ...);
// it turned out that dprintf() is semi-standard to printf to a file descriptor.
// ============================================================================
// encapsulate the housekeeping.
BOOL open_dwarf_fortress(void);
void close_dwarf_fortress(void); // is not (normally) necessary because
// it is done at exit time.
// ============================================================================
// memory reads and writes (peeks and pokes, in old BASIC terminology)
BOOL isvalidaddress(DWORD ea);
BOOL peekarb(DWORD ea, OUT void *data, DWORD len);
BYTE peekb(DWORD ea);
WORD peekw(DWORD ea);
DWORD peekd(DWORD ea);
char *peekstr(DWORD ea, OUT char *data, DWORD maxlen);
char *peekustr(DWORD ea, OUT char *data, DWORD maxlen);
BOOL pokearb(DWORD ea, const void *data, DWORD len);
BOOL pokeb(DWORD ea, BYTE data);
BOOL pokew(DWORD ea, WORD data);
BOOL poked(DWORD ea, DWORD data);
BOOL pokestr(DWORD ea, const BYTE *data);
// ============================================================================
// The name has changed because the API HAS CHANGED!
//
// Now instead of returning HERE, it always returns the start of the match.
//
// However, there is an array, here[], that is filled with the locations of
// the HERE tokens.
// (Starting at 1. here[0] is a copy of the start of the match.)
//
// The here[] array, starting at 1, is filled with the locations of the
// HERE token.
// here[0] is a copy of the start of the match.
//
// Also, the target[] array, starting at 1, is filled with the target
// addresses of all CALL, JMP, JZ, JNZ, and JCC tokens.
//
// Finally, you no longer pass it a search length. Instead, each set of
// search terms must end with an EOL.
//
//
//
// Okay, I admit this one is complicated. Treat it as a black box.
//
// Search Dwarf Fortress's code and initialized data segments for a pattern.
// (Does not search stack, heap, or thread-local memory.)
//
// Parameters: any number of search tokens, all unsigned ints.
// The last token must be EOL.
//
// 0x00 - 0xFF: Match this byte.
// EOL: End-of-list. The match succeeds when this token is reached.
// ANYBYTE: Match any byte.
// DWORD_: Followed by a dword. Exact-match the dword.
// Equivalent to 4 match-this-byte tokens.
// ANYDWORD: Match any dword. Equivalant to 4 ANYBYTEs.
// HERE: Put the current address into the here[] array.
// SKIP_UP_TO, nn: Allow up to nn bytes between the previous match
// and the next match. The next token must be a match-this-byte
// token. There is sweet, sweet backtracking.
// EITHER: Accept either of the next two tokens as a match.
// Both must be match-this-byte tokens.
// RANGE_LO, nn: Set low byte for a range comparison. DEPRECATED.
// RANGE_HI, nn: Set high byte for a range comparison, and do the
// comparison. Should immediately follow a RANGE_LO. DEPRECATED.
// BYTERANGE, nn, mm: followed by two bytes, the low and high limits
// of the range. This is the new way to do ranges.
// DWORDRANGE, nnnnnnnn, mmmmmmmm: works like BYTERANGE.
// ADDRESS: Accept any legal address in the program's text.
// DOES NOT accept pointers into heap space and such.
// CALL: Match a near call instruction to a reasonable address.
// JUMP: Match a short or near unconditional jump to a reasonable
// address.
// JZ: Match a short or long jz (jump if zero) instruction.
// JNZ: Match a short or long jnz (jump if not zero) instruction.
// JCC: Match any short or long conditional jump instruction.
// More tokens can easily be added.
//
// Returns the offset in Dwarf Fortress of the first match of the pattern.
// Also sets global variables here[] and target[].
//
// Note: starting a pattern with ANYBYTE, ANYDWORD, SKIP_UP_TO, or EOL
// is explicitly illegal.
//
#define EOL 0x100
#define ANYBYTE 0x101
//#define FF_OR_00 0x102 // deprecated
#define HERE 0x103
#define EITHER 0x104
#define SKIP_UP_TO 0x105
#define RANGE_LO 0x106 // deprecated
#define RANGE_HI 0x107 // deprecated
#define DWORD_ 0x108
#define ANYDWORD 0x109
#define ADDRESS 0x10A
#define BYTERANGE 0x10B
#define DWORDRANGE 0x10C
#define JZ 0x174
#define JNZ 0x175
#define JCC 0x170
#define CALL 0x1E8
#define JUMP 0x1E9
DWORD hexsearch2(DWORD token1, ...);
// You can use this to limit the search to a particular part of memory.
// Use 0 for start to search from the very start of Dwarf Fortress.
// Use 0 for end to stop searching at the very end of Dwarf Fortress.
void set_hexsearch2_limits(DWORD start, DWORD end);
// ============================================================================
// patch2() and verify2() support a modified subset of hex_search2() tokens:
// The names changed because the API HAS CHANGED!
//
// 0x00 - 0xFF: pokes the byte.
// EOL: End-of-list. Allows you to specify count as 10000 or so
// and terminate (with success) when this token is reached.
// DWORD_: Followed by a DWORD. Pokes the DWORD.
// CALL: given an _address_; pokes near call with the proper _delta_.
// JUMP: given an _address_; pokes near jump with the proper _delta_.
// JZ: given an _address_; assembles a near (not short) jz & delta.
// JNZ: given an _address_; assembles a near jnz & delta.
//
// Particularly note that, unlike hex_search(), CALL, JUMP, JZ, and JNZ
// are followed by a dword-sized target address.
//
// Note that patch2() does its own verify(), so you don't have to.
// TODO: is verify() useful enough to maintain?
// Make an offset in Dwarf Fortress have certain bytes.
BOOL patch2(DWORD offset, ...);
// Check that an offset in Dwarf Fortress has certain bytes.
BOOL verify2(DWORD offset, ...);
#ifdef __cplusplus
}
#endif
#endif // HEXSEARCH_H