//CallAddressEx usage //public void Function(Arg1, Arg2, Arg3); //CallAddressEx(FunctionAddress, null, false, Arg1, Arg2, Arg3); //assembly: //push Arg3 //push Arg2 //push Arg1 //call Function /// <summary> /// Extended function call with optional context, arguments, and return value. Average execution time of 1.3ms without return or 1.75ms with return. /// </summary> /// <param name="address">Xbox procedure address.</param> /// <param name="context">Cpu context. This parameter may be null.</param> /// <param name="pushArgs">Arguments to be pushed before the call is made. These are optional of course.</param> /// <returns></returns> public uint CallAddressEx(uint address, CPUContext context, bool returnValue, params object[] pushArgs) { #region Build Call Script // buffer to hold our call data System.IO.MemoryStream callScript = new System.IO.MemoryStream(); BinaryWriter call = new BinaryWriter(callScript); call.BaseStream.Position = 0; // push arguments in reverse order for (int i = pushArgs.Length - 1; i >= 0; i--) { call.Write((byte)0x68); //push call.Write(Convert.ToUInt32(pushArgs[i])); } if (context != null) { // assign registers if (context.Eax != null) { call.Write((byte)0xB8); //mov eax call.Write(Convert.ToUInt32(context.Eax)); } if (context.Ebx != null) { call.Write((byte)0xBB); //mov ebx call.Write(Convert.ToUInt32(context.Ebx)); } if (context.Ecx != null) { call.Write((byte)0xB9); //mov ecx call.Write(Convert.ToUInt32(context.Ecx)); } if (context.Edx != null) { call.Write((byte)0xBA); //mov edx call.Write(Convert.ToUInt32(context.Edx)); } if (context.Esi != null) { call.Write((byte)0xBE); //mov esi call.Write(Convert.ToUInt32(context.Esi)); } if (context.Edi != null) { call.Write((byte)0xBF); //mov edi call.Write(Convert.ToUInt32(context.Edi)); } if (context.Esp != null) { call.Write((byte)0xBC); //mov esp call.Write(Convert.ToUInt32(context.Esp)); } if (context.Ebp != null) { call.Write((byte)0xBD); //mov ebp call.Write(Convert.ToUInt32(context.Ebp)); } // assign xmm registers // remember that its a pointer, not a value you are db'ing // so we need to dump the values somewhere, then store the pointers to those... uint XmmContextBuffer = 0x10004; if (context.Xmm0 != null) { SetMemory(XmmContextBuffer, Convert.ToSingle(context.Xmm0)); call.Write(0x05100FF3); //movss xmm0 call.Write(XmmContextBuffer); //dword ptr ds:[addr] } if (context.Xmm1 != null) { SetMemory(XmmContextBuffer + 4, Convert.ToSingle(context.Xmm1)); call.Write(0x0D100FF3); //movss xmm1 call.Write(XmmContextBuffer + 4); } if (context.Xmm2 != null) { SetMemory(XmmContextBuffer + 8, Convert.ToSingle(context.Xmm2)); call.Write(0x15100FF3); //movss xmm2 call.Write(XmmContextBuffer + 8); } if (context.Xmm3 != null) { SetMemory(XmmContextBuffer + 12, Convert.ToSingle(context.Xmm3)); call.Write(0x1D100FF3); //movss xmm3 call.Write(XmmContextBuffer + 12); } if (context.Xmm4 != null) { SetMemory(XmmContextBuffer + 16, Convert.ToSingle(context.Xmm4)); call.Write(0x25100FF3); //movss xmm4 call.Write(XmmContextBuffer + 16); } if (context.Xmm5 != null) { SetMemory(XmmContextBuffer + 20, Convert.ToSingle(context.Xmm5)); call.Write(0x2D100FF3); //movss xmm5 call.Write(XmmContextBuffer + 20); } if (context.Xmm6 != null) { SetMemory(XmmContextBuffer + 24, Convert.ToSingle(context.Xmm6)); call.Write(0x35100FF3); //movss xmm6 call.Write(XmmContextBuffer + 24); } if (context.Xmm7 != null) { SetMemory(XmmContextBuffer + 28, Convert.ToSingle(context.Xmm7)); call.Write(0x3D100FF3); //movss xmm7 call.Write(XmmContextBuffer + 28); } } // call address and store result //call dword ptr ds:[CallAddress] //mov dword ptr ds:[ReturnAddress], eax //mov eax, 02DB0000h ;fake success //retn 10h call.Write((ushort)0x15FF); call.Write((uint)(ScriptBufferAddress + call.BaseStream.Position + 17)); call.Write((byte)0xA3); call.Write((uint)0x10000); call.Write(0x00DB02B8); call.Write(0x0010C200); call.Write(address); #endregion // inject call script if (callScript.Length > ScriptBufferSize) throw new Exception("Script too big. Try allocating more memory and specifying new script buffer information."); SetMemory(ScriptBufferAddress, callScript.ToArray()); call.Close(); // execute script via hijacked crashdump function FlushSocketBuffer(); SendCommand("crashdump"); // return the value of eax after the call if (returnValue) return GetUInt32(0x10000); else return 0; }
//CallAddressEx usage //public void Function(Arg1, Arg2, Arg3); //CallAddressEx(FunctionAddress, null, false, Arg1, Arg2, Arg3); //assembly: //push Arg3 //push Arg2 //push Arg1 //call Function /// <summary> /// Extended function call with optional context, arguments, and return value. Average execution time of 1.3ms without return or 1.75ms with return. /// </summary> /// <param name="address">Xbox procedure address.</param> /// <param name="context">Cpu context. This parameter may be null.</param> /// <param name="pushArgs">Arguments to be pushed before the call is made. These are optional of course.</param> /// <returns></returns> public uint CallAddressEx(uint address, CPUContext context, bool returnValue, params object[] pushArgs) { // NOTE: Documented execution timing is probably different now that we don't use straight up objects in the CPUContext // buffer to hold our call data using (System.IO.MemoryStream callScript = new System.IO.MemoryStream()) using (BinaryWriter call = new BinaryWriter(callScript)) { call.Write(LowLevel.Intel.x86.pushad); // push arguments in reverse order for (int i = pushArgs.Length - 1; i >= 0; i--) { call.Write(LowLevel.Intel.x86.push_prefix_dword); call.Write(Util.ObjectToDwordBytes(pushArgs[i])); // hack: improper conversion of floating point values } if (context != null) { // assign registers if (context.Eax.HasValue) { call.Write(LowLevel.Intel.x86.mov_eax_prefix_dword); call.Write(context.Eax.Value); } if (context.Ebx.HasValue) { call.Write(LowLevel.Intel.x86.mov_ebx_prefix_dword); call.Write(context.Ebx.Value); } if (context.Ecx.HasValue) { call.Write(LowLevel.Intel.x86.mov_ecx_prefix_dword); call.Write(context.Ecx.Value); } if (context.Edx.HasValue) { call.Write(LowLevel.Intel.x86.mov_edx_prefix_dword); call.Write(context.Edx.Value); } if (context.Esi.HasValue) { call.Write(LowLevel.Intel.x86.mov_esi_prefix_dword); call.Write(context.Esi.Value); } if (context.Edi.HasValue) { call.Write(LowLevel.Intel.x86.mov_edi_prefix_dword); call.Write(context.Edi.Value); } if (context.Esp.HasValue) { call.Write(LowLevel.Intel.x86.mov_esp_prefix_dword); call.Write(context.Esp.Value); } if (context.Ebp.HasValue) { call.Write(LowLevel.Intel.x86.mov_ebp_prefix_dword); call.Write(context.Ebp.Value); } // assign xmm registers // remember that its a pointer, not a value you are db'ing // so we need to dump the values somewhere, then store the pointers to those... if (context.Xmm0.HasValue) { SetMemory(kAddressOfXmmContextBuffer, (float)context.Xmm0.Value); // shouldnt assume its floating point input but meh call.Write(LowLevel.Intel.SSE.movss_xmm0_prefix_addr); call.Write(kAddressOfXmmContextBuffer); //dword ptr ds:[addr] } if (context.Xmm1.HasValue) { SetMemory(kAddressOfXmmContextBuffer + 4, (float)context.Xmm0.Value); call.Write(LowLevel.Intel.SSE.movss_xmm1_prefix_addr); call.Write(kAddressOfXmmContextBuffer + 4); } if (context.Xmm2.HasValue) { SetMemory(kAddressOfXmmContextBuffer + 8, (float)context.Xmm0.Value); call.Write(LowLevel.Intel.SSE.movss_xmm2_prefix_addr); call.Write(kAddressOfXmmContextBuffer + 8); } if (context.Xmm3.HasValue) { SetMemory(kAddressOfXmmContextBuffer + 12, (float)context.Xmm0.Value); call.Write(LowLevel.Intel.SSE.movss_xmm3_prefix_addr); call.Write(kAddressOfXmmContextBuffer + 12); } if (context.Xmm4.HasValue) { SetMemory(kAddressOfXmmContextBuffer + 16, (float)context.Xmm0.Value); call.Write(LowLevel.Intel.SSE.movss_xmm4_prefix_addr); call.Write(kAddressOfXmmContextBuffer + 16); } if (context.Xmm5.HasValue) { SetMemory(kAddressOfXmmContextBuffer + 20, (float)context.Xmm0.Value); call.Write(LowLevel.Intel.SSE.movss_xmm5_prefix_addr); call.Write(kAddressOfXmmContextBuffer + 20); } if (context.Xmm6.HasValue) { SetMemory(kAddressOfXmmContextBuffer + 24, (float)context.Xmm0.Value); call.Write(LowLevel.Intel.SSE.movss_xmm6_prefix_addr); call.Write(kAddressOfXmmContextBuffer + 24); } if (context.Xmm7.HasValue) { SetMemory(kAddressOfXmmContextBuffer + 28, (float)context.Xmm0.Value); call.Write(LowLevel.Intel.SSE.movss_xmm7_prefix_addr); call.Write(kAddressOfXmmContextBuffer + 28); } } // call address and store result //pushad //push Arg3 //push Arg2 //push Arg1 //call dword ptr ds:[CallAddress] //mov dword ptr ds:[ReturnAddress], eax //popad //mov eax, 02DB0000h ;fake success //retn 10h call.Write(LowLevel.Intel.x86.call_prefix_absolute); call.Write((uint)(XboxHistory.ScriptBufferAddress + call.BaseStream.Position + 18)); call.Write((byte)0xA3); call.Write(kAddressOfReturnValue); call.Write(LowLevel.Intel.x86.popad); call.Write(0xDB0000B8); call.Write(0x0010C202); call.Write(address); // inject call script if (callScript.Length > XboxHistory.ScriptBufferSize) throw new Exception("Script too big. Try allocating more memory and specifying new script buffer information."); SetMemory(XboxHistory.ScriptBufferAddress, callScript.ToArray()); } // execute script via hijacked crashdump function SendCommand("crashdump"); // return the value of eax after the call if (returnValue) return GetUInt32(kAddressOfReturnValue); else return 0; }