Skip to content

Issue with TLS callbacks if base address differs from 0x400000 #25

Closed

Description

@Fr0sT-Brutal

I'm not an expert in all this PE stuff so I don't claim to be right

I noticed an issue with TLS callbacks when I was testing ExecuteTLS(). As far as I understood the callback addresses are hardcoded relying on the fact base image address is 0x400000 (at least all the callback pointers in the sample binaries were 0x40xxxx). Thus if base address differs, they become invalid.
But base address seems to change almost always because $400000 location is frequently occupied by the module of the executable itself! So all the modules it loads later occupy completely different addresses. Thus the base address of our memorymodule could have any value and the assumption that it always >= OptionalHeader.ImageBase becomes incorrect.
AFAIU, to fix the issue these changes must be done:

  1. Change locationdelta type to signed as VirtualAlloc(nil, ...) is likely to return the pointer < $400000
  2. Keep original ImageBase value (I'd recommend just not replacing the value of module.headers.OptionalHeader.ImageBase and using module.codeBase instead in FinalizeSection)
  3. In ExecuteTLS adjust all pointers (pointer to 1st callback and the callbacks themselves) as following:
    ptr_reloc = ptr - ImageBase_old + ImageBase_new

Unfortunately I can't provide a patch because I'm developing Delphi translation of your code but I performed these changes and all callback addresses have been determined correctly. For experiments I used this article (I actually have no idea how to create TLS callback so used sample binaries from there). Testing on TLS_Example_1.exe all five callback adresses were equal to the article ones and corrected callback pointers were pointing to memory blocks corresponding the code from the article (55 8BEC 6A 00, etc)

Activity

  1. fancycode commented on Dec 20, 2015

    @fancycode
    Owner

    I don't know about the Delphi translation, but I can't reproduce this with my version. The TLS callbacks should get relocated together with the rest and so should automatically have the correct locations.

    The tests build a DLL that gets relocated (and that has TLS callbacks).

  2. dgavrilov commented on Mar 23, 2018

    @dgavrilov

    Confirm x64 crashes. Simply add std::this_thread to DLL.

  3. Fr0sT-Brutal commented on Nov 29, 2018

    @Fr0sT-Brutal
    ContributorAuthor

    An author of fork does the same calculation here FusixGit@8117a42

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions