Disassembly code of liba.so

0 25
Introduction to dynamic linkingAs mentioned earlier, there are many optimization...

Introduction to dynamic linking

As mentioned earlier, there are many optimizations in the static linking (but this does not mean that static linking is not used by anyone; in some cases, static linking still needs to be used), for example:

Wastes too much disk and memory space

Disassembly code of liba.so

Cannot be updated dynamically

To solve the aforementioned problems, dynamic linking is used.

The problems that dynamic linking needs to solve

All dynamic linking isDelays the linking process until runtime

The executable program obtained from static linking can be executed after being loaded by the operating system, because as mentioned in the previous article, during the linking process, all the code, data, and other Sections in the target files have been merged into the executable file. During this process, all the external symbols (variables, functions, etc.) used in the target files are also relocated to their positions in the virtual address space, so the executable program can run without depending on external modules (the required 'external modules' have been merged into the executable file), in summary:For static linking, during the linking stage, the relocation of symbols is directly modified in the executable file that needs to be relocated to complete the relocation.

However, this is not an easy task in dynamic linking, as dynamic linking delays the linking process until runtime, meaning during runtime:Before the entry function of the executable program is called, after the executable file and the dynamic link libraries it depends on are loaded into memory, the relocation of external symbols referenced in the executable file (that is, filling the corresponding virtual addresses in the dynamic link libraries where these symbols are called) is performed.

此时就会产生一个很关键的问题:

At this time, a very critical problem will arise:

The code segment is not writable!!

The reason does not need to be explained, if the code segment is writable, there will be no security, and it will disrupt the execution logic of the code (a writable code segment mechanism has appeared in the early days)So imagine static relocation,

It is absolutely impossible to directly modify the address at the corresponding call position of external functions/variables in the code!So how to solve this problem is

So how to solve this problem is

The core of dynamic linking

Butler Lampson once said this: adding another level of indirection

All problems in computer science can be indirectly solved by adding another layer

Although the code segment is not writable after loading, where is it writable?

Data segment!

Although we cannot directly modify the actual address of external variables/functions in the code segment, we canPlace the actual address of external variables/functions in a certain position of the data segment, let the code segment first refer to the content in the data segment, and directly modify the address saved in this data segment to the virtual address of external variables/functions during relocation to complete relocation, and thus complete dynamic linking

And this approach is the optimal approach to implement dynamic linking, and it has another name:

Address-independent code(PIC, Position-independent Code) which is the option that GCC will default to adding-fPIC

At this time, the shared library used is only one copy in the virtual memory, if the data in the shared library is used, it will be copied to each process

But this approach will generate security issues: since the data segment stores the actual virtual addresses after relocation of the executable file functions to be executed, and the data segment has write permission, this means that through some means (such as overflow), we can also overwrite its address to achieve the purpose of locating other functions, for example, if the executable file itself calls alibcFunctions, by modifying this address, it is possible to locate and uselibcAnother function system in it to achieve pop-upshellThe purpose of

Another way to implement dynamic linking

Address-independent code is undoubtedly the optimal dynamic linking solution, but if only-sharedOption without enabling-fPICThen it uses another dynamic linking method:Relocation at load time

Shared objects, also known as dynamic link libraries, are always only one copy after being loaded into physical memory, regardless of how many processes use them. However, for each process, the shared object is mapped once to the virtual address space, which means that each process space has a copy of the shared object mapping, but for different processes, the mapped addresses (base addresses) are different (most of the time).Therefore, when mapping the dynamic link library to each process during loading, it is necessary to modify the address in the instructions of the dynamic library in the physical memory according to the address of the process space (such as jump instructions or variable access, etc.)

So this generates a disadvantage:It is impossible to share the same instructions among multiple processes

Experimental observation

Some functions that may be used

  • dlopen()
  • dlsym()
  • dlerror()
  • dlclose()

dlopen()

Used to open a shared object (dynamic library) and load it into the process space, complete initialization

void *dlopen(const char *filename, int flags);

  • const char *filenameThe path to open the dynamic library

    If filename is NULL, then the returned handle is for the main program.

    If the filename is empty, return the global symbol table of the process

    Iffilenameis0, thendlopenIt will return the handle of the global symbol table, and we can find any symbol in the global symbol table at runtime and execute it. The global symbol table includes the executable file of the program itself, all shared modules loaded into the process by the dynamic linker aredlopenOpen and useRTLD_GLOBALThe module with this method.

  • const char *filenameThe way of parsing function symbols

    • RTLD_LAZYDeferred binding (the specific content will be explained later, for now let's just say)

      The binder (symbol lookup, relocation, etc.) is performed by the dynamic linker only when the function is used for the first time (not used is not bound). This improves the startup speed of the program

    • RTLD_NOWAll function binding tasks are completed when the module is loadedIf there are any undefined symbol references that cannot be bound, thendlopen()returns an error

    Choose one of the above options

RETURN VALUE

The final return value returns a pointer to a dynamic library

On success,dlopen()Returns a non-NULL handle for the loaded object. On error (file could not be found, was not readable, had the wrong format, or caused errors during loading), these functions return NULL

dlsym()

Use this function to obtain fromdlopen()The handle obtained by opening the dynamic library (handlefind the specified symbol in

void *dlsym(void *handle, const char *symbol);

  • void *handleDynamic library handle
  • const char *symbolThe symbol to be searched for

RETURN VALUEOn success, these functions return the address associated with the symbol. On failure, they return NULL; the cause of the error can be diagnosed using dlerror(3).

Successfully returns the address associated with the symbol, fails to returnNULL

dlerror()

to determine if the last call was successful

char *dlerror(void);

Each calldlopen(),dlsym()ordlclose()From now on, you can calldlerror()function to determine if the last call was successful.dlerror()The return value type ischar*If returnedNULLIndicates that the last call was successful; if not, it returns the corresponding error message

dlclose()

Close a dynamic library, unload a module that has been loaded

int dlclose(void *handle);

Experimental code

Current code relationship:

  • b.c → libb.so
  • a.c → liba.so
  • main.c → main

liba.soDepends onlibb.so

main.cAndliba.so libb.soDynamically link together asmain

1667805063_6368af87f09e9df312b1a.png!small?1667805063994

gcc -m32 -fPIC -shared b.c -o libb.so
gcc -m32 -fPIC -shared a.c -o liba.so https://www.freebuf.com/articles/system/libb.so
sudo ldconfig + current dynamic library path
gcc -m32 -fPIC main.c -o main https://www.freebuf.com/articles/system/liba.so libb.so
# Or gcc -m32 -fPIC main.c -L. liba.so libb.so -o main

b.c

#include <stdio.h>

int g_nVarB = 30;

void fnB(void)
{       
        printf("Processing in function B --- nVarB = %d \\n",g_nVarB);
}       

a.c

#include <stdio.h>

// Internal static variable
static int s_nVarA1 = 10;

// Declare global variable
int g_nVarA2 = 20;

// Declare external variable g_nVarB
extern int g_nVarB;

// Declare external function fnB
extern void fnB(void);

static void s_fnA2(void)
{
        printf("Processing in function A2 \\n");
}

void fnA3(void)
{
        printf("Processing in function A3 \\n");
}

void fnA1(void)
{
        printf("Processing in function A1 \\n");

				// Modify internal static variable
        s_nVarA1 = 11;

				// Non-static global variable
        g_nVarA2 = 20;

				// Modify external global variable
        g_nVarB = 31;

				// Call internal static function
        s_fnA2();

				// Call internal function
        fnA3();

				// Call external function
        fnB();

}

main.c

This program is very large, it may be a bit cumbersome to look at, and its functions are as follows:

  • ThroughdlopenReturns the handle of the global symbol table of this process and passes throughdlsymlocate the symbol in it
  • locateliba.soimported intomainof the symbol (if not imported, it will be outputget address failed
  • locatelibb.soimported intomainof the symbol (if not imported, it will be outputget address failed

If it exists, it will print the starting address

#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include <stdlib.h>

extern int g_nVarA2;
extern void fnA1();

typedef void (*pFunc)(void);

int main(int argc,char** argv)
{

        printf("Processing in main function \\n");

        // Print the global symbol table of the process
        void *handle = dlopen(0,RTLD_NOW);
        if ( handle == NULL)
        {
                dlerror("dlopen()");
               // exit(1);
        }

        printf("---------------------------- main function ------------------------------ \\n");

        // Print the address of variable symbols in main
        pFunc addr_main = dlsym(handle,"main");
        if (addr_main == NULL)
        {
               // dlrror("dlsym():main");
                fprintf(stderr,"get address of main failed!\\n");
               // exit(1);
        }
        else
        {
                printf("main function address is : 0x%x \\n",(unsigned int)addr_main);
        }

				// Virtual address of related symbols in liba.so
        printf("}}")"------------------------------ liba.a ------------------------------------ \\n"

        unsigned int *addr_s_nVarA1 = dlsym(handle,"s_nVarA1");
        if (addr_s_nVarA1 == NULL)
        {
               // dlrror("dlsym():liba.so:s_nVarA1");
                fprintf(stderr,"get address of s_nVarA1 failed!\\n");
               // exit(1);
        }
        else
        {
                printf("liba.so:s_nVarA1 address is : 0x%x \\n",addr_s_nVarA1);

        }

        unsigned int *addr_g_nVarA2 = dlsym(handle,"g_nVarA2");
        if (addr_g_nVarA2 == NULL)
        {
               // dlerror("dlsym():liba.so:g_nVarA2");
                fprintf(stderr,"get address of g_nVarA2 failed!\\n");
               // exit(1);
        }
        else
        {
                printf("liba.so:g_nVarA2 address is : 0x%x \\n",addr_g_nVarA2);

        }

        pFunc addr_fnA1 = dlsym(handle,"fnA1");
        if (addr_fnA1 == NULL)
        {
               // dlerror("dlsym():liba.so:fnA1");
                fprintf(stderr,"get address of fnA1 failed!\\n");
               // exit(1);
        }
        else
        {
                printf("liba.so:fnA1 function address is : 0x%x \\n",(unsigned int)addr_fnA1);

        }

        pFunc addr_s_fnA2 = dlsym(handle,"s_fnA2");
        if (addr_s_fnA2 == NULL)
        {
               // dlerror("dlsym():liba.so:s_fnA2");
                fprintf(stderr,"get address of s_fnA2 failed!\\n");
               // exit(1);
        }
        else
        {
                printf("liba.so:s_fnA2 function address is : 0x%x \\n",(unsigned int)addr_s_fnA2)}

        }

        pFunc addr_fnA3 = dlsym(handle,"fnA3");
        if (addr_fnA3 == NULL)
        {
               // dlerror("dlsym():liba.so:fnA3");
                fprintf(stderr,"get address of fnA3 failed!\\n");
               // exit(1);
        }
        else
        {
                printf("liba.so:fnA3 function address is : 0x%x \\n",(unsigned int)addr_fnA3);

        }

			  // Virtual addresses of related symbols in libb.so
        printf("---------------------------------- libb.so --------------------------------- \\n");

        unsigned int *addr_g_nVarB = dlsym(handle,"g_nVarB");
        if (addr_g_nVarB == NULL)
        {
           // dlerror("dlsym():libb.so:g_nVarB");
            fprintf(stderr,"get address of g_nVarB failed!\\n");

        }
        else
        {
            printf("libb.so:g_nVarB address is : 0x%x \\n",addr_g_nVarB);
        }

        pFunc addr_fnB = dlsym(handle,"fnB");
        if (addr_fnB == NULL)
        {
               // dlerror("dlsym():libb.so:fnB");
                fprintf(stderr,"get address of fnB failed!\\n");
               // exit(1);
        }
        else
        {
                printf("libb.so:fnB function address is : 0x%x \\n",(unsigned int)addr_fnB);
        }

        dlclose(handle);

				// Assign values to global variables in the liba dynamic library
        g_nVarA2 = 100;

				// Call parameters in liba
        fnA1();

				// Suspend the program to prevent the program from exiting,For easy observation
        while(1)
        {
            sleep(5);
        }

        return 0;
}

The loading process of dynamic libraries

Observe the dependency relationships between dynamic libraries

From the initial dependency relationship diagram, it can be seenmainProgram withliba.soAndlibb.soDependency relationships:

mainDepends onliba.so

liba.soDepends onlibb.so

You can uselddpatchelfThese two commands to observe their dependency relationships

ldd

1667805085_6368af9d342a06be6ff5e.png!small?1667805085311

patchelf

1667805098_6368afaa6ecfadf8d597b.png!small?1667805098470

1: Bootstrap of dynamic library

The dynamic linker is responsible for loading the dynamic libraries it depends on when executing the program

In the executionmainWhen, the operating system will first mapmainLoaded into memory, and then according to.interpThe information in this segment to obtainDynamic linkerpath

.interpThe content of this segment is very simple, it saves a string,This string is the path of the dynamic linker required by the executable file

ThroughobjdumpView the content of this segment

objdump -s main

1667805106_6368afb27e675ba6a4aca.png!small?1667805106604

The path to obtain the dynamic linker can be/lib/ld-linux.so.2

1667805111_6368afb7334c18af6be79.png!small?1667805111353

As can be seenThe dynamic linker itself is also a dynamic linked library (shared objectGlibcPart), but the special thing is that the dynamic linker does not depend on any dynamic library,otherwise when it is loaded, there is no one to load it for him, andThe relocation work of the global and static variables that the dynamic linker itself needs must be completed by itselfTherefore, this code of self-relocation must be completed when the dynamic linker starts, and this process is often called Bootstrap(Bootstrap),so the entry address of the dynamic library is the beginning of the bootstrap code

1667805115_6368afbb5eed54585533b.png!small?1667805115477

The dynamic linker itself is statically linked

1667805119_6368afbf1b36ee7d21db0.png!small?1667805119147

  • Therefore, executemainWhen, it will first map the dynamic linker tomainThe virtual address space of the process

    This passage will be easier to understand after reading the whole text

    At this time, the dynamic linker will first execute the bootstrap code: first locate its ownGOTTable,GOTThe first entry in the table is.dynamicShort offset addresses, through the information in this segment, the bootstrap code can obtain the relocation table and symbol table of the dynamic linker itself, thereby obtaining the relocation entry of the dynamic linker itself, and then relocate them all first. From this step on, the dynamic linker code can start using its own global variables and static variables

  • After completing the basic bootstrap,The dynamic linker willmainAnd the symbol table of the linker itself are merged into a single symbol table, which is the global symbol table

  • Subsequently, the linker begins to search for the shared objects that the executable file depends on in.dynamicThere is an entry in the segmentDT_NEEDEDIndicates the shared objects that the current executable file depends on

  • Therefore, the linker can listmainAll the required shared objects, and put these shared object names into a loading collection

    • liba.so
    • libc.so.6
  • then the linker starts to take a name of the required shared object from the set, find the corresponding file, open the file, and read the correspondingELFfile header and.dynamicsection, then map its corresponding code section and data section into the process space

  • If thisELFIf the shared object depends on other shared objects, then put the names of the dependent shared objects into the loading set. Repeat this process until all dependent shared objects are loaded into the system.

    • libb.so(liba.sodependencies )

executemainThere are two ways to observe its virtual address space after

cat /proc/PID/maps

1667805128_6368afc898a0ec25ec0d6.png!small?1667805130692

pmmp PID

1667805135_6368afcf74935876ed4bc.png!small?1667805135629

Global Symbol Table and .dynamic Table

During the static linking process, the linker will extract each symbol from each target file in the first scan to generate the global symbol table, and in the second scan, it will check each target file for symbols that need to be relocated, confirm their positions in the global symbol table, and fill this address into the reference location

due to the characteristics of dynamic linking, so each symbol can only know its specific address at runtime, so thisentrust the responsibility of generating the global symbol table to the dynamic linker

and wemainThe function of the process is todlopentodlsymprint outputmainprocess global symbol table address information of related symbols, let's first look at its execution result

1667805140_6368afd4e51f64394bae4.png!small?1667805141086

you can see the definedswhether it is a variable or a function at the beginning (static variables) inmainglobal symbol table cannot find its address, while the others are normal, why is that?

Before answering this question, let's talk about two tables.dynamicand.symtab

.symtabis not unfamiliar, that is, the symbol table, which is all the symbols in the module

.dynamicwhich is what is commonly referred to asDynamic Symbol Table,the dynamic symbol table records the export and import relationships of the module's symbols and is.symtaba subset

so for a dynamic link library,Only symbols in the dynamic symbol table will be exported, and due tostatictype characteristics, so the symbols modified by it will not be placed in the dynamic linking table,which also explains why inmainthe global symbol table cannot findliba.soandlibb.soinstaticSymbols

liba.sosymbol table and dynamic symbol table

1667805146_6368afda3cf413132ef9c.png!small?1667805146458

libb.sodynamic symbol table

1667805156_6368afe4b1c1f9a126542.png!small?1667805156749

main.sodynamic symbol table

1667805160_6368afe873ecafa3c2982.png!small?1667805160813

After completing the above process, the linker will proceed with the most important relocation and initialization process that we are concerned about

2:Relocation and Initialization

After completing the above process, the linker will perform the relocation and initialization againRevisit the relocation tables of the executable file and each shared object (.rel.),and relocate theirGOT/PLTcorrect the positions that need to be relocated in it

Due toliba.soWith more dependencies and relationships, the observation of the key tables will follow next:liba.sofor example

Relocation table .rel.

The dynamic linking will inform the linker which symbols need to be relocated through two relocation tables:

  • .rel.dynInDataReference correction (the position it corrects is locatedGOTTable (.got) and the data segment)
  • .rel.pltInFunctionsReference correction (the position it corrects is locatedGOTTable (.got.plt))

By instructionreadef -r liba.soObserveRelocation table

1667805171_6368aff3ed07fe28148e5.png!small?1667805172052

Among whichRelocation entryThere are two types of types:

  • R_386_GLOB_DAT
  • R_386_JUMP_SLOT

These two types representThe position that needs to be corrected only needs to be filled in directlyGOTThe address in the table can be corrected

Global Offset Table GOT

As mentioned before, during the execution of the program, relocation is implemented by adding an intermediate layer to achieve the function of runtime relocation, then thisThe middle layer is the Global Offset TableGOTTo implement: for example, as shown aboveliba.soWill refer tolibb.soThe global variables ing_nVarB, so inliba.soCode segment, it will take the referenceg_nVarBLocation in theg_nVarBThe address is changed toGOTTable address (GOTThe address of the corresponding table item), so it only needs to put the address into theGOTTable

GOT table in the dynamic link library

There are two in the dynamic link libraryGOTTable:

  • RelocationVariablesSymbols.got
  • RelocationFunctionsSymbols.got.plt

1667805182_6368affe265393d507909.png!small?1667805182370

As can be seen from the figure.gotAnd.got.pltThe size is24Bytes, indicating that each one has6Table items (each table item occupies 4 bytes)

And can be obtained fromOffLooking at an item:

  • .gotThe offset from the file header is0x002fe8
  • .got.pltThe offset from the file header0x003000

Let's look at it from the perspective of the loader.gotTable.got.pltThe location of the table is?

1667805200_6368b010901a52d2d63c0.png!small?1667805200687

And note one point, you can see where the first section startsVirtAddr(virtual address) is0x00000000This is because the position-independent code parameter is enabled (-fPIC)Whenliba.soThe code segment and data segment are loaded into memory, the dynamic linker will find a free space immediately, and use the starting address of this space asliba.soThe virtual starting base address, and thenVirtAddrAs the offset address

As can be seen, its4numberLOADThe starting address of the0x003ef8that is.init_arrayThe virtual address (not the final virtual address, the final virtual address needs to be added the base address at runtime)

According toSection HeadersIt can be calculated from.init_arrayAnd.gotThe offset between0x2fe8 - 0x2ef8 = 0xf0

Using0xf0 + 0x003ef8=0x3fe8That is to say.gotThe starting address

0x3ef8 + 18 = 0x4000That is to say.plt.gotThe starting address

Of course, this calculation does not mean much at the beginning, starting directly fromSection headerscan obtain theAddr

the relationship between the relocation table and the GOT table

Careful observation may find that the offset address of the symbol to be relocated in the relocation table is exactly the same as.gotand.plt.gotthe table items overlap, which also verifies what was said at the beginning, because the addresses of the symbols to be relocated in the dynamic linking all point toGOTa table itemTherefore, the dynamic linker only needs to relocateGOTrelocate the table item corresponding to the offset in the table

Among the first three entries of the GOT table are three public table items, and the functions of these three table items are as follows:

  1. got[0]the dynamic section (.dynamic(section) of this ELF
  2. got[1]the loading address oflink_mapdata structure descriptor address (module ID of this module)
  3. got[2]_dl_runtime_resolvefunction address

liba.sodisassembly code

The role of <__x86.get_pc_thunk.bx>

1667805211_6368b01bf2acb22f6420c.png!small?1667805212005

used to obtain the address of the next instruction in the function body of the function calling this function

Since the function calling this function is incall 1080 <__x86.get_pc_thunk.bx>will push the address of the next instruction onto the stack for return, so this instruction directly moves the stack pointerespthe address pointed to byebxin

⚠️ Note: Only32in the 32-bit environment, the address of the next instruction is obtained in this way, because32in the 32-bit environment does not support direct accesseipregister32it is enough in the 32-bit environment

a strange section.plt.got

Attention, attention, this is not.got.plt!!!!!!!!!!!!!!! Not important, can be skipped

1667805219_6368b023144ddead986f3.png!small?1667805219135

a program (written with C++ in Linux) calls __cxa_finalizewhen exiting the main function

__cxa_finalize and attribute 

gcc already provides destructors, which will be called by __cxa_finalize.

__cxa_finalize is called on library unload (either when a program is exiting or by a dlopen)

atexit, __cxa_atexit, and __cxa_finalize interaction

<fnA1> Analysis

1667805224_6368b0286df6233675af8.png!small?1667805224634

For convenience, here is the source code again

void fnA1(void)
{
        printf("Processing in function A1 \\n");

				// Modify internal static variable
        s_nVarA1 = 11;

				// Non-static global variable
        g_nVarA2 = 20;

				// Modify external global variable
        g_nVarB = 31;

				// Call internal static function
        s_fnA2();

				// Call internal function
        fnA3();

				// Call external function
        fnB();
}

First, let's look at11daThe two lines of code at

1128:       e8 53 ff ff ff          call   1080 <__x86.get_pc_thunk.bx>
112d:       81 c3 d3 2e 00 00       add    ebx,0x2ed3
  • call 1080 <__x86.get_pc_thunk.bx>The112dputebxin
  • add ebx,0x2ed3ebx = ebx + 0x2ed3 = 0x112d + 0x2ed3 = 0x4000

This0x4000that is.plt.gotoffset address

⚠️ When loading the dynamic library during the actual program execution, throughcallThe obtained is the virtual address, through+ 0x2ed3This offset, can successfully calculate the actual.plt.gotvirtual address

It can be seen that the operations on the variables in the relocation table after that are all based onebxto perform (variables located in the relocation table also useebxbecause.dataThe section is located.got.pltAfter)

But the function call borrows anotherSection.plt

1667805233_6368b0310bc464a75f9d2.png!small?1667805233193

About.pltIt is necessary to mention another feature Delayed Binding (PLT)

Delayed Binding (PLT)

Due to the complex access to global data and inter-module calls under dynamic linkingGOTLocation, and then indirect addressing or calling, resulting in a reduction in program execution speed of about 1%~5%. Moreover, because the linking work of dynamic linking is completed at runtime, it leads to a slower program startup speed.

During the program's execution, there will be many functions that are not used (error handling functions, unused functional modules, etc.), so there is no need to link all functions at the beginningELFThe basic idea of using the delayed binding method is that the dynamic linker performs binding (symbol lookup, relocation, etc.) only when the function is used for the first time, and does not bind the unused ones. This improves the program's startup speed

How to Implement Delayed Binding

ELFThroughPLT(Procedure Linking Table) 来实现延迟绑定

) to achieve lazy bindingIn Glibc, the function that the dynamic linker completes the binding work is called_dl_runtime_resolve()It must know where the binding occurs in which module and function, so assume its function prototype is_dl_runtime_resolve(module, function)GOTWhen calling a function of an external module, it does not jump directly throughPLTto jump, but through a callPLTthere is a corresponding item

1667805238_6368b036bba5587aa4760.png!small?1667805238881

<fnA3@plt>for example

001050 <fnA3@plt>:
    1050:       ff a3 10 00 00 00       jmp    DWORD PTR [ebx+0x10]
    1056:       68 08 00 00 00          push   0x8
    105b:       e9 d0 ff ff ff          jmp    1030 <_init+0x30>

To achieve lazy binding, the linker does not bind in the initialization phasefnA3()the address is filled into[ebx+0x10]the correspondingGOTin the table, but thepush 0x8the address is filled into[ebx+0x10]the correspondingGOTin the table, this step does not need to search for any symbols, so the cost is very low. It is obvious that the effect of the first instruction is to jump to the second instruction, which is equivalent to not performing any operation

the second instructionpush 0x8push a0x8is pushed onto the stack, and this number isfnA3This symbol reference is in the relocation table.rel.pltthe index in

Thenjmp 1030 <_init+0x30>jump to_dl_runtime_resolveThis is actually to implement_dl_runtime_resolvefunction call, after performing a series of symbol resolution and relocation operations, it willfnA3()the actual address is filled into[ebx+0x10]the correspondingGOTin the table

the next time we call<fnA3@plt>Whenjmpthe instruction can jump to the actualfnA3()In the function

你可能想看:

It is possible to perform credible verification on the system boot program, system program, important configuration parameters, and application programs of computing devices based on a credible root,

In today's rapidly developing digital economy, data has become an important engine driving social progress and enterprise development. From being initially regarded as part of intangible assets to now

5. Collect exercise results The main person in charge reviews the exercise results, sorts out the separated exercise issues, and allows the red and blue sides to improve as soon as possible. The main

4.5 Main person in charge reviews the simulation results, sorts out the separated simulation issues, and allows the red and blue teams to improve as soon as possible. The main issues are as follows

Distributed Storage Technology (Part 2): Analysis of the architecture, principles, characteristics, and advantages and disadvantages of wide-column storage and full-text search engines

b) It should have a login failure handling function, and should configure and enable measures such as ending the session, limiting the number of illegal login attempts, and automatically logging out w

Article 2 of the Cryptography Law clearly defines the term 'cryptography', which does not include commonly known terms such as 'bank card password', 'login password', as well as facial recognition, fi

Class and object - object characteristics - separate storage of member variables and member functions

Is the validity period of code signing certificates the same as that of SSL certificates, which is 1 year?

b) It should have the login failure handling function, and should configure and enable measures such as ending the session, limiting the number of illegal logins, and automatically exiting when the lo

最后修改时间:
admin
上一篇 2025年03月28日 12:31
下一篇 2025年03月28日 12:54

评论已关闭