Page 2 of 6 FirstFirst 1234 ... LastLast
Results 26 to 50 of 144

Thread: Memory reading.

  1. #26
    Join Date
    Dec 2010
    Posts
    483
    Mentioned
    30 Post(s)
    Quoted
    328 Post(s)

    Default

    Just wanted to stop in to say - of course memory reading can be detected. The most obvious way would be for them to hook/watch NtOpenProcess.

    That's all. #TheBank2017

  2. #27
    Join Date
    Nov 2016
    Posts
    2
    Mentioned
    0 Post(s)
    Quoted
    1 Post(s)

    Default

    Quote Originally Posted by alar82 View Post
    It uses AOB scan to locate resources, then just reads them. It shouldn't be any more detectable than screen color readers. As nothing is modified or injected to NXT client. No write rights to aplication are ever requested/changed. Detectability is zero as I botted a lot during double xp. Only way to jagex to catch it is by looking trough running processes and tag suspicious ones. Like wow warden anticheat or punkbuster. Jagex doesn't have anything like that :I
    There are ways around that too..
    If Jagex ever builds a comprehensive "Anti Cheat" system.

    You could run NXT on an OS inside a Hypervisor, and run your Memory reading engine Outside on the host OS. And send emulated mouse & keyboard events to the VM. No way in hell they could ever detect you then... Though it would be quite a lot more complex. Need to understand Extended Page Tables in depth.

    I'm planning to try a prototype this against the "Big Guns" at Valve VAC.

  3. #28
    Join Date
    Dec 2010
    Posts
    483
    Mentioned
    30 Post(s)
    Quoted
    328 Post(s)

    Default

    Quote Originally Posted by BotEngines View Post
    And send emulated mouse & keyboard events to the VM. No way in hell they could ever detect you
    Issue #1 : emulated video card
    Issue #2 : detection of the VMkernel with a hypervisor approach.
    Issue #3 : https://villavu.com/forum/showthread.php?t=115467


    But I do like where you're headed. Just needs some refinement. If they are looking for you they will find you no matter what you do. That's why it's a constant game of cat & mouse.

  4. #29
    Join Date
    May 2012
    Location
    Glorious Nippon
    Posts
    1,011
    Mentioned
    50 Post(s)
    Quoted
    505 Post(s)

    Default

    Quote Originally Posted by the bank View Post
    The guest OS sees all input from the host as hardware input. At least that's what I found in my brief tests with Brandon's little fake input test in that thread.

  5. #30
    Join Date
    May 2012
    Location
    Moscow, Russia
    Posts
    661
    Mentioned
    35 Post(s)
    Quoted
    102 Post(s)

    Default

    Also, for the mouse or keyboard emutalion a directinput hook can be used.
    Per aspera ad Astra!
    ----------------------------------------
    Slow and steady wins the race.

  6. #31
    Join Date
    Dec 2010
    Posts
    483
    Mentioned
    30 Post(s)
    Quoted
    328 Post(s)

    Default

    Quote Originally Posted by CynicRus View Post
    Also, for the mouse or keyboard emutalion a directinput hook can be used.
    Which they could (hypothetically) detect by iterating handle signatures looking for a start address in the range of, say, dinput8.dll. Therefore detecting that there's a directinput hook in the application being scanned. This can be done in user mode.

  7. #32
    Join Date
    Dec 2007
    Posts
    2,112
    Mentioned
    71 Post(s)
    Quoted
    580 Post(s)

    Default

    Quote Originally Posted by Citrus View Post
    The guest OS sees all input from the host as hardware input. At least that's what I found in my brief tests with Brandon's little fake input test in that thread.
    I also noticed the same on VMWare. However, it really depends on the drivers being used.

    Detecting the VM is probably the biggest issue here imo. Its pretty hard to hide the fact that you're using a VM. If they're gonna go through the effort of scanning other processes/memory, they might as well just throw in VM detection.

  8. #33
    Join Date
    Feb 2012
    Location
    Norway
    Posts
    995
    Mentioned
    145 Post(s)
    Quoted
    596 Post(s)

    Default

    Quote Originally Posted by Kasi View Post
    Detecting the VM is probably the biggest issue here imo.
    But why is that an issue?
    I feel it's like detecting that you are in fact using a PC to play RS in the sense that it doesn't really relate to whether you are botting or not, not sure how strong such a correlation would be.

    The poker bots that has been around have always been using a VM to run the client, and the bot on the physical machine. I am not sure if this has changed the past 5 years since when I was looking into it. And these bots fight against pretty good anti-cheating measures.
    Last edited by slacky; 10-01-2017 at 02:51 AM.
    !No priv. messages please

  9. #34
    Join Date
    Nov 2016
    Posts
    2
    Mentioned
    0 Post(s)
    Quoted
    1 Post(s)

    Default

    Quote Originally Posted by the bank View Post
    Issue #1 : emulated video card
    Issue #2 : detection of the VMkernel with a hypervisor approach.
    Issue #3 : ...


    But I do like where you're headed. Just needs some refinement. If they are looking for you they will find you no matter what you do. That's why it's a constant game of cat & mouse.
    I Don't mean to derail this post. I'm Fascinated by Alar82's Memory reading techniques! :-)

    1. PCI passthrough your Graphics Hardware. I'm currently using it!

    2. KVM has a feature called hidden state='on' Which removes virtualization "signatures". Fool guest into thinking it's running native hardware. Xen has even better isolation. People currently do this to get around Nvidia's detection (its against TOS). It's the only way you can install Nvidia's driver. Nvidia Want you to shell out $1000s for Tesla Workstation graphics. A real Anti-Cheat would probably detect you using DMI (firmware) information. But that could be emulated too!

    It's also Wise to enable all processor extensions and "nested" virtualization, so CPU appears native.

    3. Loved that thread & code! Looking forward to trying it! On a regular Native OS.

    I think the Cat & mouse game is quite exciting! Last I checked something like 40% of all Pro eSport Gamers Cheat. ;-) Not that I care about that realm.
    Last edited by BotEngines; 10-01-2017 at 02:54 AM.

  10. #35
    Join Date
    Dec 2007
    Posts
    2,112
    Mentioned
    71 Post(s)
    Quoted
    580 Post(s)

    Default

    Quote Originally Posted by slacky View Post
    But why is that an issue?
    I feel it's like detecting that you are in fact using a PC to play RS in the sense that it doesn't really relate to whether you are botting or not, not sure how strong such a correlation would be.
    Do you normally play rs or cs:go through a vm? Why the fuck would anyone bottleneck like that unless the game straight up didn't natively support that OS? Even in that sense. There are ways to detect the underlying OS if not baremetal and check if the game supports it.

    I personally don't know anyone that plays games legit on a VM.

    Can't speak for poker bots, haven't really looked into them.

  11. #36
    Join Date
    Feb 2012
    Location
    Norway
    Posts
    995
    Mentioned
    145 Post(s)
    Quoted
    596 Post(s)

    Default

    Quote Originally Posted by Kasi View Post
    Do you normally play rs or cs:go through a vm? Why the fuck would anyone bottleneck like that unless the game straight up didn't natively support that OS? Even in that sense. There are ways to detect the underlying OS if not baremetal and check if the game supports it.

    I personally don't know anyone that plays games legit on a VM.

    Can't speak for poker bots, haven't really looked into them.
    The year I was using Linux as my OS, I used a Windows VM alongside it for a lot of stuff (mainly due to photoshop and such tools I could only get on Windows), but then if I had the VM open already I could jump into RS every now and then, and even some CS 1.6 [CS had no native support for Linux at that time].

    But just asking me is pointless, I am/was one in a very large playerbase, only jagex, assuming they gather such data have such statistics, and know how it correlates to botting, now I am not saying it's common to use a VM, but there needs to be a solid correlation for it to be worth extra effort needed to figure out if you bot or not, which I am not sure if solely basing of if you use a VM is, or will be enough or not.

    But I am gonna get out of this thread, not really interesting for me. Just wanted to point this out.
    Last edited by slacky; 10-01-2017 at 03:31 AM.
    !No priv. messages please

  12. #37
    Join Date
    May 2012
    Location
    Moscow, Russia
    Posts
    661
    Mentioned
    35 Post(s)
    Quoted
    102 Post(s)

    Default

    Quote Originally Posted by the bank View Post
    Which they could (hypothetically) detect by iterating handle signatures looking for a start address in the range of, say, dinput8.dll. Therefore detecting that there's a directinput hook in the application being scanned. This can be done in user mode.
    Sure. If you need the kernel mode emulation, you should use somethin like this: https://github.com/djpnewton/vmulti.
    Per aspera ad Astra!
    ----------------------------------------
    Slow and steady wins the race.

  13. #38
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    It's actually way easier to detect than anything mentioned above..

    Scenario: Process A opens Process B in order to get a "HANDLE" to pass to ReadProcessMemory. To detect this, all we need to do is enumerate global list of handles.


    1. Process-B will do: NtQuerySystemInformation with SYSTEM_HANDLE_TABLE_ENTRY_INFO.
    2. Process-B will Duplicate each handle into itself.
    3. Check if that process handle is its own.
    4. If step-3 is true, get handle owner (Process-A) and scan it for RPM or hook RPM in that process (hook is nice because you can check if it is reading your process directly).
    5. Take measures such as banning or blah..


    With decent knowledge of WinAPI, almost anyone can do this and can find other ways too. Note: You don't even need to check handles.. Can do other checks too.

    C++ Code:
    #define DUPLICATE_SAME_ATTRIBUTES 0x00000004
    #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
    #define STATUS_BUFFER_OVERFLOW 0x80000005

    auto size = sizeof(SYSTEM_HANDLE_INFORMATION);
    std::unique_ptr<std::byte> info(new std::byte[size]);
    while (NtQuerySystemInformation(SystemHandleInformation, info.get(), size, &size) == STATUS_INFO_LENGTH_MISMATCH)
    {
        info.reset(new std::byte[size]); //awful.. but I know no other way..
    }

    SYSTEM_HANDLE_INFORMATION* shi = reinterpret_cast<SYSTEM_HANDLE_INFORMATION*>(info.get());

    for (auto i = 0; i < shi->Count; ++i)
    {
        SYSTEM_HANDLE_ENTRY& sh = shi->Handle[i];
       
        //Multiple options here.. Map the process and check what it does.. OR open it and check for RPM..
        HANDLE hObj = nullptr;
        HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, sh.OwnerPid);
       
        if (hProcess)
        {
            if (DuplicateHandle(hProcess, reinterpret_cast<HANDLE>(sh.HandleValue), GetCurrentProcess(), &hObj, STANDARD_RIGHTS_REQUIRED, FALSE, DUPLICATE_SAME_ACCESS))
            {
                //Scan for RPM or Hook RPM.. if it is reading us and reading structures it shouldn't be reading.. handle it.
                CloseHandle(hObj);
            }
           
            CloseHandle(hProcess);
        }
    }

    I guess you can use it for garbage and memory leak monitoring too..

    P.S. This is how VAC does it as well. But anyway, let's not derail further with "what-ifs".
    Last edited by Brandon; 10-01-2017 at 10:03 PM.
    I am Ggzz..
    Hackintosher

  14. #39
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    For mouse movements I use currently winapi stuff. There is alot of messages send to app if you look with spy++. But I could write directly into client mouse position, so windows mouse wouldn't be needed at all. Any issues with that?

  15. #40
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    It's difficult to locate right click menu options. Any help would be nice. With cheat engine preferably.
    Here is some progress:

    It's total mess but some accurate data can be extracted from there, like inventory pixel perfect location every time.

  16. #41
    Join Date
    Apr 2017
    Posts
    11
    Mentioned
    1 Post(s)
    Quoted
    5 Post(s)

    Default

    How do you personally go about finding the vtable pointers (I assume that's what you use) after each update?

    I wrote a program, Ulyaoth (C#), to match patterns, then I found reliable patterns:

    Code:
    using System;
    using System.Collections.Generic;
    
    using Gee.External.Capstone.X86;
    using IniParser;
    using IniParser.Model.Configuration;
    using PeNet;
    using PeNet.Structures;
    using Gee.External.Capstone;
    
    namespace Ulyaoth
    {
    	class Pattern
    	{
    		List<int> m_pattern = new List<int>();
    		int m_offset;
    
    		public int InstructionOffset => m_offset;
    
    		public Pattern(string mask_pattern, int offset)
    		{
    			for (int i = 0; i + 1 < mask_pattern.Length; i += 2)
    			{
    				if (mask_pattern[i] == '.' && mask_pattern[i + 1] == '.')
    				{
    					m_pattern.Add(-1);
    				}
    				else
    				{
    					int value;
    					if (Int32.TryParse(
    					    mask_pattern.Substring(i, 2), 
    					    System.Globalization.NumberStyles.HexNumber,
    					    System.Globalization.CultureInfo.InvariantCulture,
    					    out value))
    					{
    						m_pattern.Add(value);
    					}
    				}
    			}
    
    			m_offset = offset;
    		}
    
    		public bool TryMatch(byte[] data, int data_offset, out int result)
    		{
    			for (int i = 0; i + data_offset + m_pattern.Count < data.Length; ++i)
    			{
    				bool match = true;
    				for (int j = 0; j < m_pattern.Count; ++j)
    				{
    					if (!(data[data_offset + i + j] == m_pattern[j] || m_pattern[j] < 0))
    					{
    						match = false;
    						break;
    					}
    					else
    					{
    						match = true;
    					}
    				}
    
    				if (match)
    				{
    					result = i + m_offset;
    					return true;
    				}
    			}
    
    			result = 0;
    			return false;
    		}
    	}
    
    	class Program
    	{
    		static int Main(string[] arguments)
    		{
    			if (arguments.Length < 2)
    			{
    				Console.Error.WriteLine("ulyaoth <pattern> <executable>");
    				return 1;
    			}
    
    			Dictionary<string, Pattern> patterns = new Dictionary<string, Pattern>();
    			Dictionary<string, int> adjustments = new Dictionary<string, int>();
    			{
    				var parser = new FileIniDataParser();
    				var definitions = parser.ReadFile(arguments[0]);
    
    				foreach (var definition in definitions.Sections)
    				{
    					var mask_pattern = definition.Keys["signature"];
    					int offset;
    					if (Int32.TryParse(
    						definition.Keys["offset"].Substring(2),
    						System.Globalization.NumberStyles.HexNumber,
    						System.Globalization.CultureInfo.InvariantCulture,
    						out offset))
    					{
    						patterns.Add(definition.SectionName, new Pattern(mask_pattern, offset));
    					}
    
    
    					if (definition.Keys.ContainsKey("adjust"))
    					{
    						var adjustValue = definition.Keys["adjust"];
    						int adjust;
    						if (Int32.TryParse(adjustValue, out adjust))
    						{
    							adjustments.Add(definition.SectionName, adjust);
    						}
    						else
    						{
    							adjustments.Add(definition.SectionName, 0);
    						}
    					}
    					else
    					{
    						adjustments.Add(definition.SectionName, 0);
    					}
    				}
    			}
    
    			var data = System.IO.File.ReadAllBytes(arguments[1]);
    			var executable = new PeFile(data);
    			IMAGE_SECTION_HEADER text = null;
    			foreach (var section in executable.ImageSectionHeaders)
    			{
    				var name = System.Text.Encoding.UTF8.GetString(section.Name).Trim('\0');
    				if (name == ".text")
    				{
    					text = section;
    				}
    			}
    
    			if (text == null)
    			{
    				Console.Error.WriteLine("No .text section in executable.");
    				return 1;
    			}
    
    			foreach (var pattern in patterns)
    			{
    				int offset;
    				if (!pattern.Value.TryMatch(data, (int)text.PointerToRawData, out offset))
    				{
    					Console.Error.WriteLine("Failed to match pattern {0}.", pattern.Key);
    					Console.Error.WriteLine();
    				}
    				else
    				{
    					Console.WriteLine("Matched pattern {0} (+{1:X}).", pattern.Key, offset + text.VirtualAddress);
    
    					int otherMatch = 0;
    					if (pattern.Value.TryMatch(data, (int)text.PointerToRawData + offset + 1, out otherMatch))
    					{
    						Console.WriteLine("(Ambigious match.)");
    					}
    
    					using (var disassembler = CapstoneDisassembler.CreateX86Disassembler(DisassembleMode.Bit64))
    					{
    						disassembler.EnableDetails = true;
    						disassembler.Syntax = DisassembleSyntaxOptionValue.Intel;
    						var instructions = disassembler.DisassembleStream(data, offset + (int)text.PointerToRawData, text.VirtualAddress);
    
    						foreach (var instruction in instructions)
    						{
    							Console.WriteLine("{0:X}: \t {1} \t {2}", instruction.Address, instruction.Mnemonic, instruction.Operand);
    							Console.WriteLine("\t Id = {0}", instruction.Id);
    							foreach (var operand in instruction.ArchitectureDetail.Operands)
    							{
    								string operandValue = null;
    								switch (operand.Type)
    								{
    									case X86InstructionOperandType.FloatingPoint:
    										operandValue = operand.FloatingPointValue.Value.ToString("X");
    										break;
    									case X86InstructionOperandType.Immediate:
    										operandValue = operand.ImmediateValue.Value.ToString("X");
    										break;
    									case X86InstructionOperandType.Memory:
    										operandValue = "-->";
    										break;
    									case X86InstructionOperandType.Register:
    										operandValue = operand.RegisterValue.Value.ToString();
    										break;
    								}
    
    								Console.WriteLine("\t\t {0} = {1}", operand.Type, operandValue);
    
    								// Handle Memory Operand.
    								//
    								// ...
    								if (operand.Type == X86InstructionOperandType.Memory)
    								{
    									Console.WriteLine("\t\t\t Base Register = {0} ", operand.MemoryValue.BaseRegister);
    									Console.WriteLine("\t\t\t Displacement = {0:X} ", operand.MemoryValue.Displacement + offset + (int)text.PointerToRawData + instruction.Bytes.Length + 0xC00 + adjustments[pattern.Key]);
    									Console.WriteLine("\t\t\t Index Register = {0}", operand.MemoryValue.IndexRegister);
    									Console.WriteLine("\t\t\t Index Register Scale = {0}", operand.MemoryValue.IndexRegisterScale);
    									Console.WriteLine("\t\t\t Segment Register = {0}", operand.MemoryValue.SegmentRegister);
    								}
    								Console.WriteLine();
    							}
    
    							break;
    						}
    					}
    				}
    			}
    
    			return 0;
    		}
    	}
    }
    I can't post my offsets.ini publicly since it contains copyrighted Jagex binary code from the client. Feel free to PM me.

    To find the offsets, I first found the target offset (e.g., vtable pointers) via Cheat Engine and did an xref to in IDA. From there, I used Radare2 to manually add the method and create the signature:

    Code:
    af+ <hex offset to method from IDA> <name of function> f
    afb+ <name of function> 0 <size of function from IDA>
    zaf <name of function>
    z
    The format of the INI is like so:

    Code:
    [entry_name]
    ; machine code (hexadecimal doublets) with .. as a masking character
    signature = XX......XXXX
    ; offset of op-code giving displacement (i.e., offset to value)
    offset = 0x0
    ; adjust (optional): value to add to displacement
    adjust = 0
    My current offsets.ini works from mid-November to now, and most entries work all the way up to the update back the week of September 11 2017.

    The value of "Displacement" gives you of the offset from the base of the executable.

    Here's my research into the data structures:

    Code:
    # terms
    world units: 512x multiple of tile coordinates, usually floating point
    tile units: aka in-game tile
    
    ## types
    float: 4-byte single-precision floating point number
    short: 2-byte integer
    int: 4-byte integer
    pointer: 8-byte (native word) pointer to object
    string: EA STL string type
    
    # table [npc_table, object_table, player_table]
    - pool of used/unused objects
    - NPC/object/players all have tables (*_table in offsets.ini)
    +0x0000: pointer to pool
    +0x????: pointer to array of indices for used entities
    +0x????: pointer to array of indices for unused entities
    +0x????: number of entities currently used (+0x0008?)
    
    # item table ([global_item_table])
    0x0000: pointer to item list
    0x0008: list count, int
    0x000C: list capacity (?)
    
    # item table entry, not virtual
    - size: ? (didn't write it down)
    +0x0020: item ID, int
    +0x0024: quantity, int
    +0x0090: X (world units), float
    +0x0094: Y (world units), float
    +0x0098: Z (world units), float
    
    # NPC table entry, virtual [npc_vtable]
    - size: 0x2000 bytes
    0x0128: name, string
    0x035c: X (world units), float
    0x0360: Y (world units), float
    0x0364: Z (world units), float
    0x05a7: animation ID (short)
    0x0ff0: NPC ID #1 (sometimes different), int
    0x0ff0: NPC ID #2 (always correct), int
    0x1028: current health, int (? seems too high, maybe wrong)
    
    # Player table entry, virtual
    - size: 0x2000 bytes (?)
    0x0128: name, string
    0x035c: X (world units), float
    0x0360: Y (world units), float
    0x0364: Z (world units), float
    0x05a7: animation ID (short)
    0x1028: current health, int (? seems too high, maybe wrong)
    
    # Object table entry, virtual [object_vtable]
    - size: 0x298 bytes long
    +0x0134: X (tile units), int
    +0x0138: Z (tile units), int
    +0x013c: Y (world units), int
    +0x0100: pointer to structure
    	+0x0020: object ID (valid for static objects, maybe dynamic)
    +0x0178: object ID (only valid for dynamic [?] objects)
    
    # heap [heap]
    - size: 0x130 bytes
    - there's a size field and reserved field somewhere, didn't write it down
    +0x0000: pointer to arena
    +0x0044: pointer to free stack head
    +0x0048: pointer to free stack tail
    I never began reverse engineering the client since I moved on to other things and stopped playing RuneScape. A good starting point would be the functions that instantiate the aforementioned objects and methods in the vtable.

  17. #42
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    That's superb coding skills you have there. Hm as I understand you use PeNet library to get sections executable of something erm. Then something-something of disassemble it with Capstone library,..Er.
    My thing is much much simple, find pattern, read whats there, although it's limited.
    I wonder did you make something useful with it. Bot program of sorts or send data to simba.

    It's quite stable now:
    Inventory:
    MiniMap:
    Main issue is that there isn't much of a point to bot rs3. Its just too easy.

  18. #43
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    Hey guys even if I wanted to put my source up. It needs 2 additional libraries to work, but those are probably copyrighted. Blackbone for memory searching and imgui for debug. Can I zip whole stuff and upload?
    https://github.com/DarthTon/Blackbone
    https://github.com/ocornut/imgui

  19. #44
    Join Date
    Dec 2011
    Posts
    2,147
    Mentioned
    221 Post(s)
    Quoted
    1068 Post(s)

    Default

    Quote Originally Posted by alar82 View Post
    Hey guys even if I wanted to put my source up. It needs 2 additional libraries to work, but those are probably copyrighted. Blackbone for memory searching and imgui for debug. Can I zip whole stuff and upload?
    https://github.com/DarthTon/Blackbone
    https://github.com/ocornut/imgui
    You can attach a .ZIP to a post, yeah. Looking forward to it, nice screenshots!

  20. #45
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    Err forum upload limit is 100kb so mediafire it is.
    Source:
    It needs visual studio 2015 and windows sdk.
    https://github.com/pp9999/MemoryError/tree/master
    As source is kinda messy:
    https://github.com/pp9999/MemoryError/releases

    We can setup github if srl community is interested and fix the code.

    Usage for nubs: Put MemoryError.dll into simbas plugins folder, you need simba 64 bit build and rs NXT client not old java.
    Simba 64 bit build here:http://l0.lt/builders/master either Simba.x86_64-win64 7z or exe.
    Script for RS3 festival area, super boring and 1 click activity.
    festivalmining.simba
    Simba Code:
    program Test;
    //{$I srl-6/SRL.simba}
    {$loadlib MemoryError}
    var
    Count:Int32;

    begin
    wait(random(199));
    SetupRSReading(True,True);
    repeat
    wait(240+random(6500));
    if (CheckPAnim3) then begin wait(100+random(11500)) end else
    begin
    Count:=Count+1;
    if FindAobj([106662],1,20,0,0,0) then
    begin
    wait(2410+random(6500));
    end;
    end;
    until(Count>1999)
    end.

    Log into your throwaway account and run the script.
    It should take a minute max to find all needed addresses.
    If debug has appeared there are some keys to see if it works correctly:
    f1 = ground items
    f2 = other players
    f6 = inventory
    f7 = active objects debug, above script uses this.
    f8 = all objects debug
    f9 = decor objects
    f10 = npcs
    With shift key they will be on minimap, no rotation however.
    f11 = interfaces mess
    f12 = hide always on debug
    Page up = imps on minimap
    shift+ctrl+f4 = varpbits


  21. #46
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    Code:
    FindAobj([106662],1,20,0,0,0)
    Variables order is:
    1st ids separated by commas([106662,1,2,3])
    2nd how many ids(1 if 1 in [ ])
    3rd range in tiles how far look for (20)
    4th and 5th click adjustments in pixels
    6th is how to click: 0 left click,1 right click,2 move to,3 return true and do nothing.

  22. #47
    Join Date
    Sep 2014
    Location
    C:\Simba\
    Posts
    565
    Mentioned
    9 Post(s)
    Quoted
    71 Post(s)

    Default

    Good work @alar82;
    I'm curious about OffSets.h
    Are these offsets not changed whenever an update changes anything concerning entities. Like for example if they add another attribute to an object, would this not mean that some of these pointer offsets get moved slightly or are they always added to the end? Alternatively does this page update whenever you run your "updater"?
    Feel free to ask me any questions, I will do my best to answer them!

    Previously known as YouPee.

  23. #48
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    Quote Originally Posted by Joopi View Post
    Good work @alar82;
    I'm curious about OffSets.h
    Are these offsets not changed whenever an update changes anything concerning entities. Like for example if they add another attribute to an object, would this not mean that some of these pointer offsets get moved slightly or are they always added to the end? Alternatively does this page update whenever you run your "updater"?
    I think offsets will change when game engine is modified, so far once per half a year. Adding new attribute to ncps would broke it too me thinks and I have to manually re-find them. No updater, only cheat engine.

  24. #49
    Join Date
    Apr 2017
    Posts
    11
    Mentioned
    1 Post(s)
    Quoted
    5 Post(s)

    Default

    I'm trying to understand your code. To find things of interest (e.g., NPCs), you:

    1) Search the entire address space of the RuneScape process for a specific pattern.
    2) When the pattern is matched, you extract relevant data and resume searching the address space from that point forward.

    Is that right?

    There is a better way of doing that. There is a table of NPCs stored at 0x6E3018. How the game keeps track of which NPCs are valid or not I don't know, but valid NPCs have a vtable pointer set to 0x52D370. (These values are relative to the base address of the process and thus change due to ASLR; they also change every update, but with the pattern matching tool I posted earlier, given the right pattern, the correct offsets can be regenerated without trouble after each update).

    Thus, I am able to iterate over the NPCs without much of a performance penalty using ReadProcessMemory:

    Code:
    NPC 458 ('Father Urhney'):
    - location: 3209, 869, 3149
    - animation: 65535
    NPC 12348 ('Giant rat'):
    - location: 3218, 555, 3198
    - animation: 65535
    NPC 16898 ('Ysondria'):
    - location: 3220, 325, 3183
    - animation: 65535
    NPC 8828 ('Giant rat'):
    - location: 3225, 194, 3190
    - animation: 65535
    NPC 8828 ('Giant rat'):
    - location: 3238, 799, 3171
    - animation: 65535
    NPC 8829 ('Giant rat'):
    - location: 3230, 234, 3182
    - animation: 65535
    The same goes for players, objects, and ground items. I've yet to find where the root GUI node/widget(s) are stored, but the heirarchy can be generate from any widget downwards. (I don't think the parent widget is stored).

    Here's a program you can run to see for yourself:

    Code:
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    namespace Meeseek
    {
    	class Program
    	{
    		static readonly IntPtr NPC_TABLE = new IntPtr(0x6E3018);
    		static readonly IntPtr NPC_VTABLE = new IntPtr(0x52D370);
    
    		[DllImport("kernel32.dll", SetLastError = true)]
    		static extern bool ReadProcessMemory(
    			IntPtr hProcess,
    			IntPtr lpBaseAddress,
    			[Out] byte[] lpBuffer,
    			int dwSize,
    			out IntPtr lpNumberOfBytesRead);
    
    		static int Main(string[] args)
    		{
    			Console.WriteLine("Enter PID:");
    			int pid = Int32.Parse(Console.ReadLine());
    			var process = Process.GetProcessById(pid);
    			var executable = process.Modules[0];
    			var npcTableAddress = new IntPtr(executable.BaseAddress.ToInt64() + NPC_TABLE.ToInt64());
    			var npcVTableAddress = new IntPtr(executable.BaseAddress.ToInt64() + NPC_VTABLE.ToInt64());
    
    			IntPtr numBytesRead;
    			IntPtr npcTablePointer;
    			{
    				byte[] buffer = new byte[8];
    				ReadProcessMemory(process.Handle, npcTableAddress, buffer, 8, out numBytesRead);
    				if (numBytesRead.ToInt64() < 8)
    				{
    					Console.WriteLine("Woops, didn't read enough bytes (NPC table pointer)!");
    					return 1;
    				}
    
    				npcTablePointer = new IntPtr(BitConverter.ToInt64(buffer, 0) + 0x20);
    			}
    
    			byte[] npcBuffer = new byte[0x10f0];
    			for (int i = 0; i < 255; ++i)
    			{
    				IntPtr npcPointer = new IntPtr(npcTablePointer.ToInt64() + i * npcBuffer.Length);
    				if (!ReadProcessMemory(process.Handle, npcPointer, npcBuffer, npcBuffer.Length, out numBytesRead))
    				{
    					Console.WriteLine("Woops, didn't read enough bytes (NPC {0})!", i);
    					return 1;
    				}
    
    				// EASTL string but most NPC names are short enough
    				IntPtr vtable = new IntPtr(BitConverter.ToInt64(npcBuffer, 0));
    				if (vtable != npcVTableAddress)
    				{
    					continue;
    				}
    
    				string name = "";
    				for (int j = 0; j < 0x20; ++j)
    				{
    					if (npcBuffer[j + 0x128] == 0)
    					{
    						break;
    					}
    					name += Char.ConvertFromUtf32(npcBuffer[j + 0x128]);
    				}
    
    				int x = (int)(BitConverter.ToSingle(npcBuffer, 0x35c) / 512);
    				int y = (int)(BitConverter.ToSingle(npcBuffer, 0x360));
    				int z = (int)(BitConverter.ToSingle(npcBuffer, 0x364) / 512);
    				ushort animation = BitConverter.ToUInt16(npcBuffer, 0xd48);
    				int id = BitConverter.ToInt32(npcBuffer, 0xff4);
    
    				Console.WriteLine("NPC {0} ('{1}'):", id, name);
    				Console.WriteLine("- location: {0}, {1}, {2}", x, y, z);
    				Console.WriteLine("- animation: {0}", animation);
    			}
    
    			return 0;
    		}
    	}
    }
    Enter the PID of the RuneScape 2 NXT client (64-bit only) before the next update. You must be logged in to a world (otherwise it'll try and deference a null pointer and everything fails). It's not very pretty but it was just a proof of concept.
    Last edited by Kompromaus; 04-25-2018 at 03:18 AM.

  25. #50
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    Did you know that different nxt executable is loaded based on your operating system windows 7 vs 10.
    However I see you take exe modulebase and add NPC_TABLE.
    Using that info I came up with these numbers: RS base:13f830000+6E3018=13FF13018
    Points to:
    ce.jpg
    Erm is it right spot?
    Looks like random bytes=)
    Edit: compiled your program, it gives error "Woops, didn't read enough bytes (NPC {0})!"
    Changed bit a code to wait so i could see errors.
    Code:
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Threading;
    
    namespace Meeseek
    {
        class Program
        {
            static readonly IntPtr NPC_TABLE = new IntPtr(0x6E3018);
            static readonly IntPtr NPC_VTABLE = new IntPtr(0x52D370);
    
            [DllImport("kernel32.dll", SetLastError = true)]
            static extern bool ReadProcessMemory(
                IntPtr hProcess,
                IntPtr lpBaseAddress,
                [Out] byte[] lpBuffer,
                int dwSize,
                out IntPtr lpNumberOfBytesRead);
    
            static int Main(string[] args)
            {
                Console.WriteLine("Enter PID:");
                int pid = Int32.Parse(Console.ReadLine());
                var process = Process.GetProcessById(pid);
                var executable = process.Modules[0];
                var npcTableAddress = new IntPtr(executable.BaseAddress.ToInt64() + NPC_TABLE.ToInt64());
                Console.WriteLine("npcTableAddress:"+npcTableAddress.ToString("X"));
                var npcVTableAddress = new IntPtr(executable.BaseAddress.ToInt64() + NPC_VTABLE.ToInt64());
                Console.WriteLine("npcVTableAddress:" + npcVTableAddress.ToString("X"));
    
                IntPtr numBytesRead;
                IntPtr npcTablePointer;
                {
                    byte[] buffer = new byte[8];
                    ReadProcessMemory(process.Handle, npcTableAddress, buffer, 8, out numBytesRead);
                    if (numBytesRead.ToInt64() < 8)
                    {
                        Console.WriteLine("Woops, didn't read enough bytes (NPC table pointer)!");
                        Thread.Sleep(15000);
                        return 1;
                    }
                    //Console.WriteLine("buffer:" + buffer);
                    npcTablePointer = new IntPtr(BitConverter.ToInt64(buffer, 0) + 0x20);
                    Console.WriteLine("buffer:" + npcTablePointer.ToString("X"));
                }
    
                byte[] npcBuffer = new byte[0x10f0];
                for (int i = 0; i < 255; ++i)
                {
                    IntPtr npcPointer = new IntPtr(npcTablePointer.ToInt64() + i * npcBuffer.Length);
                    if (!ReadProcessMemory(process.Handle, npcPointer, npcBuffer, npcBuffer.Length, out numBytesRead))
                    {
                        Console.WriteLine("Woops, didn't read enough bytes (NPC {0})!", i);
                        Thread.Sleep(15000);
                        return 1;
                    }
    
                    // EASTL string but most NPC names are short enough
                    IntPtr vtable = new IntPtr(BitConverter.ToInt64(npcBuffer, 0));
                    if (vtable != npcVTableAddress)
                    {
                        continue;
                    }
    
                    string name = "";
                    for (int j = 0; j < 0x20; ++j)
                    {
                        if (npcBuffer[j + 0x128] == 0)
                        {
                            break;
                        }
                        name += Char.ConvertFromUtf32(npcBuffer[j + 0x128]);
                    }
    
                    int x = (int)(BitConverter.ToSingle(npcBuffer, 0x35c) / 512);
                    int y = (int)(BitConverter.ToSingle(npcBuffer, 0x360));
                    int z = (int)(BitConverter.ToSingle(npcBuffer, 0x364) / 512);
                    ushort animation = BitConverter.ToUInt16(npcBuffer, 0xd48);
                    int id = BitConverter.ToInt32(npcBuffer, 0xff4);
    
                    Console.WriteLine("NPC {0} ('{1}'):", id, name);
                    Console.WriteLine("- location: {0}, {1}, {2}", x, y, z);
                    Console.WriteLine("- animation: {0}", animation);
                    Thread.Sleep(15000);
                }
    
                return 0;
            }
        }
    }
    Result looks same, magical bytes?
    pp.jpg

Page 2 of 6 FirstFirst 1234 ... LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •