@@ -663,10 +663,10 @@ AurieStatus YYTK::Zeus::FindSlotAllocationFunction(
663663 if (!YYObjectBase_Add)
664664 return AURIE_UNAVAILABLE;
665665
666- // Disassemble 48 bytes at the function
666+ // Disassemble 96 bytes at the function
667667 auto instructions = Memory::DmDisassembleInstructionByRange (
668668 YYObjectBase_Add,
669- 0x30
669+ 0x60
670670 );
671671
672672 // Find the first call, and trace the target
@@ -694,6 +694,180 @@ AurieStatus YYTK::Zeus::FindSlotAllocationFunction(
694694 return AURIE_SUCCESS;
695695}
696696
697+ // These functions are only present on x64. Having them on x86 would just clutter up the headers.
698+ static AurieStatus FindCurrentFunction (
699+ IN const YYTK::YYRunnerInterface& Interface,
700+ OUT YYTK::RFunction*** g_pFunction
701+ )
702+ {
703+ using namespace YYTK ;
704+
705+ // Disassemble YYGetPtr.
706+ auto instructions = Memory::DmDisassembleInstructionByRange (
707+ Interface.YYGetPtr ,
708+ 0x50
709+ );
710+
711+ // It just so happens the first mov that has a
712+ // memory operand references the the_functions array.
713+ // It usually looks like mov <64bit register>, [the_functions]
714+ for (auto & instruction : instructions)
715+ {
716+ // The instruction has to be a mov
717+ if (instruction.info .mnemonic != ZYDIS_MNEMONIC_MOV)
718+ continue ;
719+
720+ // The instruction has to have 2 operands
721+ // The first one (operands[0]) is the register being moved into
722+ // The second one (operands[1]) is the address
723+ if (instruction.info .operand_count != 2 )
724+ continue ;
725+
726+ ZydisDecodedOperand& first_operand = instruction.operands [0 ];
727+ ZydisDecodedOperand& second_operand = instruction.operands [1 ];
728+
729+ // We have to be moving INTO a register, not FROM a register
730+ if (first_operand.type != ZYDIS_OPERAND_TYPE_REGISTER)
731+ continue ;
732+
733+ // Get the register we're moving into, and get the largest variant of that register
734+ ZydisRegister largest_enclosing = ZydisRegisterGetLargestEnclosing (
735+ ZYDIS_MACHINE_MODE_LONG_64,
736+ first_operand.reg .value
737+ );
738+
739+ // If the register is already in its largest variant, we can continue
740+ // This is to filter out the_numb (the number of elements in the functions array),
741+ // which is being moved in the same way, just into a 32-bit register.
742+
743+ if (largest_enclosing != first_operand.reg .value )
744+ continue ;
745+
746+ // We have to be moving from a memory location, not from a register
747+ if (second_operand.type != ZYDIS_OPERAND_TYPE_MEMORY)
748+ continue ;
749+
750+ // There has to be an offset... duh
751+ if (!second_operand.mem .disp .has_displacement )
752+ continue ;
753+
754+ // Calculate the absolute address
755+ ZyanU64 call_address = 0 ;
756+ ZydisCalcAbsoluteAddress (
757+ &instruction.info ,
758+ &second_operand,
759+ instruction.runtime_address ,
760+ &call_address
761+ );
762+
763+ // It's a pointer to a pointer, we dereference it once to
764+ // get the actual pointer to the first element in the array
765+ *g_pFunction = reinterpret_cast <RFunction**>(call_address);
766+ return AURIE_SUCCESS;
767+ }
768+
769+ return AURIE_OBJECT_NOT_FOUND;
770+ }
771+
772+ static AurieStatus FindFunctionsArrayWithScriptPerform (
773+ IN const YYTK::YYRunnerInterface& Interface,
774+ IN YYTK::RFunction** g_pFunctions,
775+ OUT YYTK::RFunction*** FunctionsArray
776+ )
777+ {
778+ using namespace YYTK ;
779+
780+ // Disassemble instructions at Script_Perform
781+ auto instructions = Memory::DmDisassembleInstructionByRange (
782+ Interface.Script_Perform ,
783+ 0x100
784+ );
785+
786+ // Get the first MOV instruction that references g_pFunctions.
787+ auto current_function_iterator = std::find_if (
788+ instructions.begin (),
789+ instructions.end (),
790+ [g_pFunctions](IN const ZydisDisassembledInstruction& Instruction) -> bool
791+ {
792+ // Looking for a mov.
793+ if (Instruction.info .mnemonic != ZYDIS_MNEMONIC_MOV)
794+ return false ;
795+
796+ const ZydisDecodedOperand& first_operand = Instruction.operands [0 ];
797+ const ZydisDecodedOperand& second_operand = Instruction.operands [1 ];
798+
799+ // Our mov should be moving to a register from a memory location.
800+ if (first_operand.type != ZYDIS_OPERAND_TYPE_REGISTER)
801+ return false ;
802+
803+ if (second_operand.type != ZYDIS_OPERAND_TYPE_MEMORY)
804+ return false ;
805+
806+ // Calculate the absolute address
807+ ZyanU64 call_address = 0 ;
808+ ZydisCalcAbsoluteAddress (
809+ &Instruction.info ,
810+ &second_operand,
811+ Instruction.runtime_address ,
812+ &call_address
813+ );
814+
815+ // Return true if it's referencing g_pFunctions.
816+ return call_address == reinterpret_cast <ZyanU64>(g_pFunctions);
817+ }
818+ );
819+
820+ if (current_function_iterator == instructions.end ())
821+ {
822+ DbgPrintEx (LOG_SEVERITY_ERROR, " Failed to find g_pFunction reference in Script_Perform!" );
823+ return AURIE_OBJECT_NOT_FOUND;
824+ }
825+
826+ // Get the index that current_function_iterator belongs to.
827+ ptrdiff_t current_function_index = std::distance (instructions.begin (), current_function_iterator);
828+
829+ // Go back in the instructions list from the g_pFunctions-referencing instruction until
830+ // we find another MOV instruction referencing a memory address.
831+ //
832+ // This will be our the_functions reference.
833+ for (auto i = (current_function_index - 1 ); i > 0 ; i--)
834+ {
835+ // Looking for a mov.
836+ if (instructions[i].info .mnemonic != ZYDIS_MNEMONIC_MOV)
837+ continue ;
838+
839+ const ZydisDecodedOperand& first_operand = instructions[i].operands [0 ];
840+ const ZydisDecodedOperand& second_operand = instructions[i].operands [1 ];
841+
842+ // Our mov should be moving to a register from a memory location.
843+ if (first_operand.type != ZYDIS_OPERAND_TYPE_REGISTER)
844+ continue ;
845+
846+ if (second_operand.type != ZYDIS_OPERAND_TYPE_MEMORY)
847+ continue ;
848+
849+ // Calculate the absolute address
850+ ZyanU64 call_address = 0 ;
851+ ZydisCalcAbsoluteAddress (
852+ &instructions[i].info ,
853+ &second_operand,
854+ instructions[i].runtime_address ,
855+ &call_address
856+ );
857+
858+ if (call_address)
859+ {
860+ DbgPrintEx (LOG_SEVERITY_TRACE, " Found the_functions reference in Script_Perform (%s)" , instructions[i].text );
861+
862+ *FunctionsArray = reinterpret_cast <RFunction**>(call_address);
863+ return AURIE_SUCCESS;
864+ }
865+ }
866+
867+ DbgPrintEx (LOG_SEVERITY_ERROR, " Failed to find the_functions reference in Script_Perform!" );
868+ return AURIE_OBJECT_NOT_FOUND;
869+ }
870+
697871AurieStatus YYTK::Zeus::YYC::FindFunctionsArray (
698872 IN const YYRunnerInterface& Interface,
699873 OUT RFunction*** FunctionsArray
@@ -702,7 +876,37 @@ AurieStatus YYTK::Zeus::YYC::FindFunctionsArray(
702876 if (!Interface.Code_Function_Find )
703877 return AURIE_MODULE_INTERNAL_ERROR;
704878
705- // Disassemble this function
879+ // If we have Script_Perform (and YYGetPtr, but we always seem to have that),
880+ // chances are we're on a newer runner. We can use the v5-exclusive method of finding g_pFunction,
881+ // and then scanning Script_Perform for references to the true functions array.
882+ //
883+ // This bypasses the 2024.14 changes that make referencing the functions array from Code_Function_Find impossible.
884+ if (Interface.Script_Perform && Interface.YYGetPtr )
885+ {
886+ // Get the g_pFunction pointer. It will contain nullptr at this point, but we don't care about it's actual value.
887+ RFunction** g_pFunction = nullptr ;
888+ AurieStatus last_status = FindCurrentFunction (
889+ Interface,
890+ &g_pFunction
891+ );
892+
893+ // Make sure we got it.
894+ if (!AurieSuccess (last_status))
895+ return last_status;
896+
897+ last_status = FindFunctionsArrayWithScriptPerform (
898+ Interface,
899+ g_pFunction,
900+ FunctionsArray
901+ );
902+
903+ return last_status;
904+ }
905+
906+ // If the required functions are unavailable, we resort to the old method of scanning Code_Function_Find, and
907+ // either have it work or crash the runner.
908+
909+ // Disassemble the Code_Function_Find function.
706910 auto instructions = Memory::DmDisassembleInstructionByRange (
707911 Interface.Code_Function_Find ,
708912 0x200
0 commit comments