相关指令记录
ARDP
ADRP <reg> <imm>
- 从PC相对地址到4KB页添加一个直接值
线程局部存储 (TLS) 是一种存储持续期(storage duration),对象的存储是在线程开始时分配,线程结束时回收,每个线程有该对象自己的实例。这种对象的链接性(linkage)可以是静态的也可是外部的。
在Windows
上TLS
的存储结构为:
静态TLS
需要使用 __declspace(thread) 变量
进行标识, 当编译器进行打包时会将它存储到特定的节中(.tls
)它将会变成一个tls
模板, 在程序进行线程创建时将会开辟一个足够大的空间将tls模板
数据复制进去(tls副本
), 所以每个线程访问与修改它时互不干扰.
这个问题我也是折腾了很久, 在网上找了很久的资料基本上都是讲的TLS Callback
,反调试相关的, 然后看了<<Windows PE权威指南>>
虽然有说静态TL是如何存储的,但是没有例子,只是说了下 不过已经知道TLS
是存储在哪儿的 那不就好办了? 书上说的是“当创建线程时,加载器通过将线程环境块(TEB)的地址放入FS寄存器来传递线程的TLS数组地址。距TEB开头0x2C的位置处的字段ThreadLocalStoragePointer指向TLS数组”
书上这里说的是32位的, 64位的可以自己去查 TEB相关字段偏移 也就是说只要我将 TLS
模板中的数据先写到一块内存中, 然后将数据首地址写入这个数组中就好了?
跟着书上说的我去试了下, 发现有大坑!!!, 然后我仔细想了想了TEB
在每个线程都是不一样的, 所以我加进去的只是TLS副本
也就是说我只给我当前获取到TEB
的那个线程加进去了, 其他的还是没有然后这样会导致我的程序在开新线程的时候获取不到TLS
数据… 离谱吧, 所以在程序中不开线程访问是莫问题滴… 但是对于简单的程序还好, 要是遇到网络相关操作的一个线程?? 所以这个算只是解决了半个问题??.. 现在大概是知道问题所在, 我修改的只是TLS
副本, 所以我只需要修改加载器的TLS
模板数据就可以了? (也就是说将加载器TLS
数据模板替换为我主程序的模板数据). 但是我怎么知道加壳程序TLS
模板存储位置呢.. 带着这个问题又去查资料, 果然在Github
找到一个外国佬写的pe_loader而且它支持静态TLS
的加载, 所以我去看了他的代码 tls_support.cpp
他获取这个模板数据首地址是硬搜的, 先拿到TLS
表然后去内存匹配
芜湖~ 这不就是我想要的? 好像他的代码挺复杂的, 不过已经知道办法了只需要撸代码了
可移植的
是指该文件格式的通用性,可用于许多种不同的操作系统和体系结构中。PE文件格式封装了Windows操作系统加载可执行程序代码时所必需的一些信息。这些信息包括动态链接库、API导入和导出表、资源管理数据和线程局部存储数据。在Windows NT操作系统中,PE文件格式主要用于EXE文件、DLL文件、.sys(驱动程序)和其他文件类型。可扩展固件接口(EFI)技术规范书中说明PE格式是EFI环境中的标准可执行文件格式。开头为DOS头部。winnt.h
1 | typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header |
C
内存溢出问题1 | #include <stdio.h> |
编译后运行直接段错误,查了半天硬是没查出问题, 后突然想到是不是栈空间满了,查了下百度果不其然
在我的Linux下使用ulimit -s
查出我的系统栈空间大小为8kb
而我开辟了1MB
的空间所以出现段错误
将 buff
变量加上static
关键字或缩小buff
大小即可解决问题,还可以将buff
作为全局变量
某部队进行新兵队列训练,将新兵从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,凡报到二的出列,剩下的向小序号方向靠拢,再从头开始进行一至三报数,凡报到三的出列,剩下的向小序号方向靠拢,继续从头开始进行一至二报数。。。,以后从头开始轮流进行一至二报数、一至三报数直到剩下的人数不超过三人为止。
该题意思是,队列编号第一轮编号1~2
叫到 2
的出列, 第二轮编号1~3
叫到3
的出列,反复循环直到剩余人数不超过3
人
c
1 | #include <stdio.h> |
报错说我重复定义了这个重载函数, 网上查了半天,说是头文件没有写#ifndef & #define
可是我明明写了, 还是不起作用,又说使用关键字extern
, 可是我就是要定义在头文件里面,后来看了c++
的全局重载函数,发现都写了inline
修饰,于是试了试结果成功了
使用inline
修饰这个函数,使用它修饰需要考虑自己的代码是否符合inline
inline
相关在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。
我理解它其实就是和宏定义差不多,宏定义会在编译器编译时进行宏展开,而inline
做的事情其实和它是差不多的,只不过inline
会有一些使用限制.
然后我这个错误在还未链接时是没有错误的,在链接是就出现了重复定义,使用inline
就正好解决了我遇到的问题,因为它在编译时就会把这个函数转换为内联函数,所以在链接时就不会出现重复定义问题