Skip to content

Conversation

OldGamesCracking
Copy link
Contributor

I'm sorry if this is a bit lengthy, but sometimes I need to hear what's on my mind :)

TL;DR: Proper version of #3588 also handles #3615 (and hopefully some more cases)


Now a bit of prose:

It somehow bugged me that my initial solution (#3588) did not work and I thought about it for some while.
I finally decided to set up VS to see stuff in-depth (thanks for the easy setup!).

To find the root cause, let's use the latest version of x64dbg (snapshot_2025-07-04_16-03) so we can have a common .exe to talk about and also use the last version from the development branch (with the reverted Pull Request)
If I copy the first 2 instructions at the entry point and then do a pattern search in the Current Module (as d2k2-git did in #3615 ), the following instruction is created (argv in cbInstrFindAllMem):

findallmem 7FF6EB890000, 4883EC28E813040000, 3D000

Which returns 1 result at Address=7FF6EB897E40.
The first page that is added to searchPages is the one starting at 7FF6EB890000 (Module Base) which makes sense.
So far, so good, that's what we expected.

But now let's try to find that pattern manually at - let's say - 1 byte before the entry point by typing in the following command:

findallmem 7FF6EB897E3F, 4883EC28E813040000, 3D000

The first page that is added to searchPages is now the one starting at 7FF6EB8B1000 (Start of .rdata) which is way beyond the place where we wanted to start the search from.
And as expected, we get zero results.

So, my initial idea was that page.address >= addr is wrong. The page must start BEFORE the searchaddress, hence page.address <= addr would seem like the right logic.
And if I change the code to that, my manual command works fine. But now "Search in Current Module" breaks. Why is that so? There must be a problem in the second part of the &&-conjunction.

Let's re-write it a bit so we can place a breakpoint on the interesting part:

if (page.address <= addr)
{
    if (find_size == -1)
    {
        searchPages.push_back(page);
    }
    else
    {
        if (page.address + page.size <= addr + find_size)
        {
            searchPages.push_back(page);
        }
    }
}

It's easy to see that now it adds all pages where the address of the last byte is below the end of the searchrange which is ok, but it will now also add pages where page.address + page.size < addr would be true and we would get pages that we don't want.
Also now that I can step through the code in the debugger, I see what's the problem: The second page of the module (Address=7FF6EB891000 Size=20000) is within the searchrange, but past the base address, so it's not added.

So what we really need is a "does one range overlap the other?" logic:

if (
    (page.address <= addr && addr < page.address + page.size) ||
    (addr <= page.address && page.address < addr + find_size)
)
{
    // One (partially or fully) overlaps the other
    searchPages.push_back(page);
}
else if (find_size == -1 && addr <= page.address)
{
    // Not overlapping, but past the address
    searchPages.push_back(page);
}

Of course you could merge that together, I just find it easier to read.

Testcases:

  • Full module search:
findallmem 7FF6EB890000, 4883EC28E813040000, 3D000

Result:

searchPages[0] = {address=0x7ff6eb890000}
...
searchPages[7] = {address=0x7ff6eb8cc000}

  • Searchrange fully within one page:
findallmem 7FF6EB897E3F, 4883EC28E813040000, 100

Result:

searchPages[0] = {address=0x7ff6eb891000}

  • Searchrange at page borders:
findallmem 7FF6EB891000, 4883EC28E813040000, 20000

Same result

  • Searchrange within previous page:
findallmem 7FF6EB890000, 4883EC28E813040000, 1000

Result:

searchPages[0] = {address=0x7ff6eb890000}

No results (as expected)

  • Search through all pages
findallmem 0, 4883EC28E813040000, -1

Result:

searchPages[0] = {address=0x7FFE0000}
...
searchPages[53] = {address=0x7FF8B6067000}

So I'm somewhat sure that this will solve it :)


But now a new problem arises: It is now possible to get searchresults below addr and beyond addr + find_size (which was also the case before), but this is easily fixable by filtering the results.

if ((result < addr) || ((find_size != -1) && (addr + find_size <= result)))
{
    continue;
}

So for example take the following command:

findallmem 7FF6EB897E3F, CC, 100

Without filtering: 2347 results
With filtering: 4 results

Fingers crossed, nothing breaks this time.

@mrexodia
Copy link
Member

mrexodia commented Jul 7, 2025

Thanks a lot for following up on this!

@d2k2-git could you give it a try perhaps?

@d2k2-git
Copy link
Contributor

d2k2-git commented Jul 8, 2025

Thanks a lot for following up on this!

@d2k2-git could you give it a try perhaps?

i have made a quick test with the pattern search in module with the build from this PR. looks good for me.

@OldGamesCracking
Copy link
Contributor Author

I hate it when my brain does this, but this morning an edge case came to my mind :D

It was possible that the searchpattern overlaps the area to search in. My second commit should have fixed that.

For example

findallmem 7FF6EB897E00, 4883EC28E813040000, 0x41

previously yielded 1 result, although only 1 byte of the pattern is within [7FF6EB897E00 .. 7FF6EB897E00 + 0x41] (pattern starts at 7FF6EB897E40). Now this result is excluded.

@mrexodia
Copy link
Member

Various people tested this and looks like it fixed a bunch of issues, so thanks a lot!

@mrexodia mrexodia merged commit 529f36d into x64dbg:development Jul 19, 2025
3 checks passed
@mrexodia
Copy link
Member

Are you on the Discord @OldGamesCracking?

@OldGamesCracking
Copy link
Contributor Author

Are you on the Discord @OldGamesCracking?

Yes, but I'm on vacation right now, so I can't join your server until next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants