diff --git a/core/logic/smn_core.cpp b/core/logic/smn_core.cpp index 8e90d40310..6065d7230d 100644 --- a/core/logic/smn_core.cpp +++ b/core/logic/smn_core.cpp @@ -863,10 +863,17 @@ enum NumberType static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params) { + // new parameter added after SM 1.12; defaults to 0 for backwards compatibility + cell_t offset = 0; + if (params[0] >= 3) + { + offset = params[3]; + } + #ifdef PLATFORM_X86 - void *addr = reinterpret_cast(params[1]); + void *addr = reinterpret_cast(reinterpret_cast(params[1]) + offset); #else - void *addr = pseudoAddr.FromPseudoAddress(params[1]); + void *addr = reinterpret_cast(reinterpret_cast(pseudoAddr.FromPseudoAddress(params[1])) + offset); #endif if (addr == NULL) @@ -895,10 +902,17 @@ static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params) static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params) { + // new parameter added after SM 1.12; defaults to 0 for backwards compatibility + cell_t offset = 0; + if (params[0] >= 5) + { + offset = params[5]; + } + #ifdef PLATFORM_X86 - void *addr = reinterpret_cast(params[1]); + void *addr = reinterpret_cast(reinterpret_cast(params[1]) + offset); #else - void *addr = pseudoAddr.FromPseudoAddress(params[1]); + void *addr = reinterpret_cast(reinterpret_cast(pseudoAddr.FromPseudoAddress(params[1])) + offset); #endif if (addr == NULL) @@ -950,6 +964,66 @@ static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params) return 0; } +static cell_t LoadAddressFromAddress(IPluginContext *pContext, const cell_t *params) +{ + cell_t offset = params[2]; + +#ifdef PLATFORM_X86 + void **addr = reinterpret_cast(reinterpret_cast(params[1]) + offset); +#else + void **addr = reinterpret_cast(reinterpret_cast(pseudoAddr.FromPseudoAddress(params[1])) + offset); +#endif + + if (addr == NULL) + { + return pContext->ThrowNativeError("Address cannot be null"); + } + else if (reinterpret_cast(addr) < VALID_MINIMUM_MEMORY_ADDRESS) + { + return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr); + } + +#ifdef PLATFORM_X86 + return reinterpret_cast(*addr); +#else + return pseudoAddr.ToPseudoAddress(*addr); +#endif +} + +static cell_t StoreAddressToAddress(IPluginContext *pContext, const cell_t *params) +{ + cell_t offset = params[4]; + +#ifdef PLATFORM_X86 + void **addr = reinterpret_cast(reinterpret_cast(params[1]) + offset); +#else + void **addr = reinterpret_cast(reinterpret_cast(pseudoAddr.FromPseudoAddress(params[1])) + offset); +#endif + + if (addr == NULL) + { + return pContext->ThrowNativeError("Address cannot be null"); + } + else if (reinterpret_cast(addr) < VALID_MINIMUM_MEMORY_ADDRESS) + { + return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr); + } + +#ifdef PLATFORM_X86 + void *store = reinterpret_cast(params[2]); +#else + void *store = pseudoAddr.FromPseudoAddress(params[2]); +#endif + + if (params[3]) + { + SourceHook::SetMemAccess(addr, sizeof(addr), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC); + } + + *addr = store; + return 0; +} + static cell_t IsNullVector(IPluginContext *pContext, const cell_t *params) { cell_t *pNullVec = pContext->GetNullRef(SP_NULL_VECTOR); @@ -1157,6 +1231,8 @@ REGISTER_NATIVES(coreNatives) {"RequireFeature", RequireFeature}, {"LoadFromAddress", LoadFromAddress}, {"StoreToAddress", StoreToAddress}, + {"LoadAddressFromAddress", LoadAddressFromAddress}, + {"StoreAddressToAddress", StoreAddressToAddress}, {"IsNullVector", IsNullVector}, {"IsNullString", IsNullString}, {"LogStackTrace", LogStackTrace}, diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 1927015680..e97e231c0c 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -736,10 +736,11 @@ enum Address * @param addr Address to a memory location. * @param size How many bytes should be read. * If loading a floating-point value, use NumberType_Int32. + * @param offset Amount of bytes the base address needs to be offsetted by before loading. * @return The value that is stored at that address. * @error Address is null or pointing to reserved memory. */ -native any LoadFromAddress(Address addr, NumberType size); +native any LoadFromAddress(Address addr, NumberType size, int offset = 0); /** * Store up to 4 bytes to a memory address. @@ -750,9 +751,32 @@ native any LoadFromAddress(Address addr, NumberType size); * If storing a floating-point value, use NumberType_Int32. * @param updateMemAccess If true, SourceMod will set read / write / exec permissions * on the memory page being written to. + * @param offset Amount of bytes the base address needs to be offsetted by before storing. * @error Address is null or pointing to reserved memory. */ -native void StoreToAddress(Address addr, any data, NumberType size, bool updateMemAccess = true); +native void StoreToAddress(Address addr, any data, NumberType size, bool updateMemAccess = true, int offset = 0); + +/** + * Load an address value from a memory address. + * + * @param addr Address to a memory location. + * @param offset Amount of bytes the base address needs to be offsetted by before loading. + * @return The address value that is stored at that address. + * @error Address is null or pointing to reserved memory. + */ +native Address LoadAddressFromAddress(Address addr, int offset = 0); + +/** + * Store an address value to the given address. + * + * @param addr Address to a memory location. + * @param data Address value to store at the address. + * @param updateMemAccess If true, SourceMod will set read / write / exec permissions + * on the memory page being written to. + * @param offset Amount of bytes the base address needs to be offsetted by before storing. + * @error Address is null or pointing to reserved memory. + */ +native void StoreAddressToAddress(Address addr, Address data, bool updateMemAccess = true, int offset = 0); methodmap FrameIterator < Handle { // Creates a stack frame iterator to build your own stack traces.