1
0

y_writemem.inc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. #if defined _INC_y_writemem
  2. #endinput
  3. #endif
  4. #define _INC_y_writemem
  5. /*+
  6. * <library name="y_writemem">
  7. * <section>
  8. * Description
  9. * </section>
  10. * Write to any absolute address in the SA:MP server in pure PAWN with embedded
  11. * assembly (i.e. a new native). Calls "VirtualProtect" to make writes safe.
  12. * <section>
  13. * Version
  14. * </section>
  15. * 1.0
  16. * <section>
  17. * Functions
  18. * </section>
  19. * <subsection>
  20. * API
  21. * </subsection><ul>
  22. * <symbol name="WriteMem">Write data to an address.</symbol>
  23. * </ul><section>
  24. * Definitions
  25. * </section><ul>
  26. * <symbol name="asm">Convert a stream of assembly to a cell.</symbol>
  27. * </ul><section>
  28. * Variables
  29. * </section>
  30. * <subsection>
  31. * Static
  32. * </subsection><ul>
  33. * <symbol name="YSI_g_sWriteMem">The assembly.</symbol>
  34. * </ul>
  35. * </library>
  36. *//** *//*
  37. Legal:
  38. Version: MPL 1.1
  39. The contents of this file are subject to the Mozilla Public License Version
  40. 1.1 the "License"; you may not use this file except in compliance with
  41. the License. You may obtain a copy of the License at
  42. http://www.mozilla.org/MPL/
  43. Software distributed under the License is distributed on an "AS IS" basis,
  44. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  45. for the specific language governing rights and limitations under the
  46. License.
  47. The Original Code is the YSI framework.
  48. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  49. Portions created by the Initial Developer are Copyright C 2011
  50. the Initial Developer. All Rights Reserved.
  51. Contributors:
  52. Y_Less
  53. koolk
  54. JoeBullet/Google63
  55. g_aSlice/Slice
  56. Misiur
  57. samphunter
  58. tianmeta
  59. maddinat0r
  60. spacemud
  61. Crayder
  62. Dayvison
  63. Ahmad45123
  64. Zeex
  65. irinel1996
  66. Yiin-
  67. Chaprnks
  68. Konstantinos
  69. Masterchen09
  70. Southclaws
  71. PatchwerkQWER
  72. m0k1
  73. paulommu
  74. udan111
  75. Thanks:
  76. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  77. ZeeX - Very productive conversations.
  78. koolk - IsPlayerinAreaEx code.
  79. TheAlpha - Danish translation.
  80. breadfish - German translation.
  81. Fireburn - Dutch translation.
  82. yom - French translation.
  83. 50p - Polish translation.
  84. Zamaroht - Spanish translation.
  85. Los - Portuguese translation.
  86. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes for
  87. me to strive to better.
  88. Pixels^ - Running XScripters where the idea was born.
  89. Matite - Pestering me to release it and using it.
  90. Very special thanks to:
  91. Thiadmer - PAWN, whose limits continue to amaze me!
  92. Kye/Kalcor - SA:MP.
  93. SA:MP Team past, present and future - SA:MP.
  94. Optional plugins:
  95. Gamer_Z - GPS.
  96. Incognito - Streamer.
  97. Me - sscanf2, fixes2, Whirlpool.
  98. */
  99. #include <a_samp>
  100. #include "..\YSI_Storage\y_amx"
  101. #include "..\YSI_Coding\y_hooks"
  102. #include "..\YSI_Core\y_utils"
  103. #tryinclude "..\amx\windows\import_table"
  104. #tryinclude <amx_assembly\windows\import_table>
  105. #tryinclude "..\amx_assembly\windows\import_table"
  106. #tryinclude "..\..\amx_assembly\windows\import_table"
  107. forward WriteMem(addr, value);
  108. #define asm(%0,%1,%2,%3) ((0x%0<<0)|(0x%1<<8)|(0x%2<<16)|(0x%3<<24))
  109. /*
  110. cell AMX_NATIVE_CALL
  111. n_WriteMem(AMX * amx, cell * params)
  112. {
  113. if (params[0] == 8)
  114. {
  115. DWORD
  116. oldp;
  117. VirtualProtect((cell *)params[1], 4, PAGE_EXECUTE_READWRITE, &oldp);
  118. *((cell *)params[1]) = params[2];
  119. }
  120. return 0;
  121. }
  122. BECOMES:
  123. align 16
  124. push ebp
  125. mov ebp, esp
  126. push esi
  127. mov esi, [ebp+12]
  128. cmp dword ptr [esi], 8
  129. jnz short loc_ret
  130. mov ecx, [esi+4]
  131. lea eax, [ebp+12]
  132. push eax
  133. push 40h
  134. push 4
  135. push ecx
  136. call ds:__imp__VirtualProtect@16 ; LOOK THIS UP FIRST.
  137. mov edx, [esi+4]
  138. mov eax, [esi+8]
  139. mov [edx], eax
  140. loc_ret:
  141. xor eax, eax
  142. pop esi
  143. pop ebp
  144. retn
  145. */
  146. static
  147. YSI_g_sWriteMem[] =
  148. {
  149. asm(CC,CC,CC,CC), asm(CC,CC,CC,CC), asm(CC,CC,CC,CC), asm(CC,CC,CC,CC),
  150. asm(55,8B,EC,56), asm(8B,75,0C,83), asm(3E,08,75,1A), asm(8B,4E,04,8D),
  151. //asm(45,0C,50,6A), asm(40,6A,04,51), asm(FF,15,8C,11), asm(4A,00,8B,56),
  152. asm(45,0C,50,6A), asm(40,6A,04,51), asm(FF,15,00,00), asm(00,00,8B,56),
  153. asm(04,8B,46,08), asm(89,02,33,C0), asm(5E,5D,C3,CC)
  154. },
  155. YSI_g_iWriteMemAddr = 0;
  156. stock WriteMem(addr, value)
  157. {
  158. static ptr = -1;
  159. // Push addr and value.
  160. #emit PUSH.S value
  161. #emit PUSH.S addr
  162. #emit PUSH.C 8
  163. if (ptr == -1)
  164. {
  165. // ptr = COD + CIP - DAT + <distance to nop #1>
  166. // Modified from code by Zeex_.
  167. #emit LCTRL 6 // CIP
  168. #emit LOAD.alt AMX_HEADER_COD
  169. #emit ADD
  170. #emit ADD.C 84
  171. #emit STOR.pri ptr
  172. // NOP #1 = SYSREQ.D
  173. #emit CONST.pri 135
  174. #emit SREF.pri ptr
  175. // ptr += 4
  176. #emit LOAD.pri ptr
  177. #emit ADD.C 4
  178. #emit STOR.pri ptr
  179. // NOP #2 = address
  180. #emit LOAD.pri YSI_g_iWriteMemAddr
  181. #emit SREF.pri ptr
  182. }
  183. // Reserve space for SYSREQ.D WriteMem.
  184. #emit NOP
  185. #emit NOP
  186. // Pop native arguments.
  187. #emit STACK 12
  188. }
  189. static WM_Shift(from, to, data[], len = sizeof (data))
  190. {
  191. if (FALSE)
  192. {
  193. WriteMem(0, 0);
  194. }
  195. while (from < len)
  196. {
  197. data[to++] = data[from++];
  198. }
  199. }
  200. hook OnScriptInit()
  201. {
  202. // 00 4A 61 98
  203. new
  204. addr = GetImportPointer("VirtualProtect");
  205. #emit LOAD.S.alt addr
  206. // Get the offset to the long call address.
  207. #emit CONST.pri YSI_g_sWriteMem
  208. #emit ADD.C 42
  209. #emit STOR.S.pri addr
  210. // Write the real address.
  211. #emit SREF.S.alt addr
  212. // Align the code to a 16-byte boundary.
  213. addr = AMX_GetGlobalAddress(YSI_g_sWriteMem);
  214. switch (addr & 15)
  215. {
  216. case 0:
  217. {
  218. WM_Shift(4, 0, YSI_g_sWriteMem);
  219. }
  220. case 4:
  221. {
  222. WM_Shift(4, 3, YSI_g_sWriteMem);
  223. addr += 12;
  224. }
  225. case 8:
  226. {
  227. WM_Shift(4, 2, YSI_g_sWriteMem);
  228. addr += 8;
  229. }
  230. case 12:
  231. {
  232. WM_Shift(4, 1, YSI_g_sWriteMem);
  233. addr += 4;
  234. }
  235. default:
  236. {
  237. P:E("Cannot relocate YSI_g_sWriteMem");
  238. }
  239. }
  240. YSI_g_iWriteMemAddr = addr;
  241. return 1;
  242. }