S
S
StillDontKnowMyName2020-05-07 13:46:40
C++ / C#
StillDontKnowMyName, 2020-05-07 13:46:40

Am I on the right track to remove unnecessary functions from memory at runtime?

Preface
I am writing an addition to another program in the form of a DLL. DllMain runs the functions that are needed to collect data and inject hooks into the functions of the program itself. It is important that information is collected only once at startup, and then all the work is done by hooks, that is, after the introduction of hooks, the functions that implemented hooks and collected data are no longer needed and it is advisable to get rid of them for security purposes.

The way I found to remove functions
1. At the end of each function to be removed, bits are declared, which can then be found:

#define fn_limit _asm{\
_emit 0x9c\
_emit 0x9c\
_emit 0x9c\
_emit 0x9c\
_emit 0x9c}

void DoSomething
{
    /// do something

    fn_limit;
}


2. In a hook or in a function that called DoSomething, starting from the function pointer, the search for a sequence of bits from the end of the function begins, which gives information about the size of the function and the ability to remove the function from memory using And here the first question arises: is it possible and necessary after that call delete to transfer the cleared memory to the OS? My theoretical method (I haven’t tested it yet, but the opinion of experienced coders is interesting) What happens if you create something like an advanced singleton that will dynamically allocate memory for a class at startup, and after executing the functions, you can call a function that will simply erase the class and release the memory?memset(DoSomething, 0, calculated_size);




class MainClass
{
  MainClass* Get()
  {
    if (main_class == nullptr)
      main_class = new(std::nothrow) MainClass;

    return main_class;
  }

  void Destroy()
  {
    DWORD old;

    VirtualProtect(main_class, sizeof(MainClass), PAGE_EXECUTE_READWRITE, &old);
    memset(main_class, 0, sizeof(MainClass));
    VirtualProtect(main_class, sizeof(MainClass), old, &old);

    delete main_class;
    main_class = nullptr;
  }

  void DoSomething();

private:
  MainClass* main_class{ nullptr };
}

void main()
{
  MainClass* mc = MainClass::Get();

  if (mc)
    mc->DoSomething();

  MainClass::Destroy();
}

Answer the question

In order to leave comments, you need to log in

3 answer(s)
J
jcmvbkbc, 2020-05-07
@StillDontKnowMyName

the first question: is it possible and necessary to call delete after that in order to transfer the cleared memory to the OS for use?

If you look into the C++ standard where the delete operator is defined , you will see that it can only be called on memory allocated by new. Since you did not allocate memory for the function code through new, you cannot call delete either.
What happens if we create something like an advanced singleton that will dynamically allocate memory for a class at startup, and after the functions are executed, it will be possible to call a function that will simply erase the class and release the memory?

In principle, this can be done. But the above implementation doesn't even come close to doing what you expect.
At first it may seem that it works. Memory, however, will not be returned to the OS. Then you may notice that the code also remains in place. Then you might notice that the program sometimes crashes because of a NULL pointer in some other object. In short, if you can debug this, you will have more knowledge of how everything works at the assembler level. If you can't, then wonderful crashes await your program, and no less wonderful bug reports await you.

V
Vasily Melnikov, 2020-05-07
@BacCM

It will not be possible to free memory from functions. Allocating memory for a class is allocating memory for its data, not for code.
Even clearing the memory with zeros is doubtful - the code may well be placed in a memory area where writing is prohibited.
The easiest way is to make a dynamically loaded library with service functions, and after working out your functions, unload it from memory.

O
Odissey Nemo, 2020-05-07
@odissey_nemo

This is the curse of the infinite memory paradigm of modern computers and development environments.
The OS-RV (RSX11-M) SM-4 (PDP-11) had such a magical tool, the Task Builder (TKB).
For a large task (for example, in Fortran), which does not fit into the memory allocated to it (64 kilobytes) of the OS, a program module loading descriptor was created (in everyday life - an overlay), i.e. a clear formalized description of which module calls another module when, and which of them are in memory at the same time.
Naturally, this approach required a clear understanding of its task, designing the structure of modules and other disciplines of thinking.
And it turned out literally magical! The program will work. pulls his DK disk: (2.5 megabytes! Not kilobytes!) and asks: insert another disk for me, on which my second part is written!
Here it is, what magic was possible! Today you don't even know which libraries are linked from where and why))) And if there is not enough memory, you need to take another computer. Or get fired

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question