该文介绍了如何使用指针中一些未使用的位来隐藏一些数据。

When we write C code, pointers are everywhere. We can make a little extra use of pointers and sneak in some extra information in them. To pull this trick off, we exploit the natural alignment of data in memory.

Data in memory is not stored at any arbitrary address. The processor always reads memory in chunks at the same size as its word size; and thus for efficiency reasons, the compiler assigns addresses to entities in memory as multiples of their size in bytes. Therefore on a 32 bit processor, a 4-byte int will definitely reside at a memory address that is evenly divisible by 4.

Here, I am going to assume a system where size of int and size of pointer are 4 bytes.

Now let us consider a pointer to an int. As said above, the int can be located at memory addresses 0x1000 or 0x1004 or 0x1008, but never at 0x1001 or 0x1002 or 0x1003 or any other address that is not divisible by 4.
Now, any binary number which is a multiple of 4 will end with 00.
This essentially means that for any pointer to an int, its 2 lower order bits are always zero.

Now we have 2 bits which communicate nothing. The trick here is put our data into these 2 bits, use them whenever we want and then remove them before we make any memory access by dereferencing the pointer.

Since bitwise operations on pointers don’t go well with the C standard, We will be storing the pointer as an unsigned int.

The following is a naive snippet of the code for brevity. See my github repo - hide-data-in-ptr for the full code.

void put_data(int *p, unsigned int data)
{
assert(data < );
*p |= data;
} unsigned int get_data(unsigned int p)
{
return (p & );
} void cleanse_pointer(int *p)
{
*p &= ~;
} int main(void)
{
unsigned int x = ;
unsigned int p = (unsigned int) &x; printf("Original ptr: %u\n", p); put_data(&p, ); printf("ptr with data: %u\n", p);
printf("data stored in ptr: %u\n", get_data(p)); cleanse_pointer(&p); printf("Cleansed ptr: %u\n", p);
printf("Dereferencing cleansed ptr: %u\n", *(int*)p); return ;
}

This will give the following output:

Original ptr:  3216722220
ptr with data: 3216722223
data stored in ptr: 3
Cleansed ptr: 3216722220
Dereferencing cleansed ptr: 701

We can store any number that can be represented by 2 bits in the pointer. Using put_data(), the last 2 bits of the pointer are set as the data to be stored. This data is accessed using get_data(). Here, all bits except the last 2 bits are overwritten as zeroes there by revealing our hidden data.

cleanse_pointer() zeroes out the last 2 bits, making the pointer safe for dereferencing. Note that while some CPUs like Intel will let us access unaligned memory locations, certain others like ARM CPU will fault. So, always remember to keep the pointer pointed to an aligned location before dereferencing.

Is this used anywhere in the real world?

Yes, it is. See the implementation of Red Black Trees in the Linux kernel (link).

The node of the tree is defined using:

struct rb_node {
unsigned long __rb_parent_color;
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));

Here unsigned long __rb_parent_color stores:
1. the address of the parent node

2. the node’s color.

The color is represented as 0 for Red and 1 for Black.

Just like in the earlier example, this data is sneaked into the ‘useless’ bits of the parent pointer.

Now see, how the parent pointer and the color information is accessed:

/* in rbtree.h */
#define rb_parent(r) ((struct rb_node *)((r)->__rb_parent_color & ~3))/* in rbtree_augmented.h */
#define __rb_color(pc) ((pc) & 1)
#define rb_color(rb) __rb_color((rb)->__rb_parent_color)

转:Hide data inside pointers(在指针中隐藏数据)的更多相关文章

  1. 在图像中隐藏数据:用 Python 来实现图像隐写术

    什么是“隐写术”? 隐写术是将机密信息隐藏在更大的信息中,使别人无法知道隐藏信息的存在以及隐藏信息内容的过程.隐写术的目的是保证双方之间的机密交流.与隐藏机密信息内容的密码学不同,隐写术隐瞒了传达消息 ...

  2. NOPI读取模板导出(Excel中追加数据)

    在Controller里,我们定义一个FileResult的Action,返回值是一个文件形式被浏览器下载下来. [HttpGet] public FileResult ExportProductLi ...

  3. Java生鲜电商平台-SpringCloud微服务开发中的数据架构设计实战精讲

    Java生鲜电商平台-SpringCloud微服务开发中的数据架构设计实战精讲 Java生鲜电商平台:   微服务是当前非常流行的技术框架,通过服务的小型化.原子化以及分布式架构的弹性伸缩和高可用性, ...

  4. 访问cv::Mat中的数据时遇到的指针类型问题

    在用Opencv的时候由于下图原本的图像尺寸是1111*1111,要进行resize,代码如下: cv::Mat img = cv::imread("//Users//apple//td3/ ...

  5. 聚集表(clustered table)data page中的数据行可以无序

    误区 一直以为只要一个表含有聚集索引,那么在data page中的数据行是排序的.比如原来data page中有1.2.4.5.6这样四条记录,那么我要插入3这条记录,应该是先将456三条记录往后移, ...

  6. [MySQL]load data local infile向MySQL数据库中导入数据时,无法导入和字段不分离问题。

    利用load data将文件中的数据导入数据库表中的时候,遇到了两个问题. 首先是load data命令无法执行的问题: 命令行下输入load data local infile "path ...

  7. Web网页中动态数据区域的识别与抽取 Dynamical Data Regions Identification and Extraction in Web Pages

    Web网页中动态数据区域的识别与抽取 Dynamical Data Regions Identification and Extraction in Web Pages Web网页中动态数据区域的识别 ...

  8. load data导txt文件进mysql中的数据

    1.实验内容: 利用SQL语句“load data ”将“.txt”文本文件中的数据导入到mysql中 2.实验过程: 首先我创了一个txt(也可以是其他的),设置其编码为utf-8,在windows ...

  9. 报错:此版本的SQL Server Data Tools与此计算机中安装的数据库运行时组件不兼容

    在Visual Studio 2012中使用Entity Framework,根据模型生成数据库时,报如下错误: 无法在自定义编辑器中打开Transact-SQL文件此版本的SQL Server Da ...

随机推荐

  1. mysql 4种启动方式

    mysql 4种启动方式 都是去调用mysqld文件 1. mysqld 启动 进入mysqld文件所在目录(/../libexec/mysqld) ./mysqld --defaults-file= ...

  2. Android(Xamarin)之旅(一)

    Xamarin废话我就不多说了. 就是一款编写Android和IOS应用的IDE,从Visual Studio2010就开始有个这个插件.只要发展什么的,我觉得在这里说还不如自己去百度呢. 入正题: ...

  3. 编译jsoncpp库以及要注意的问题

    原创文章,转载请注明原作者与本文原始URL. 版本:jsoncpp-src-0.5.0.zip简介:jsoncpp是用cpp实现的json库,可以拼装,解析,生成json串.我们要把他编译成动态库.这 ...

  4. java设计模式之外观模式(门面模式)

    针对外观模式,在项目开发和实际运用中十分频繁,但是其极易理解,下面就简要介绍一下. 一.概念介绍 外观模式(Facade),他隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口.这种类型的设计 ...

  5. 无法远程连接ubuntu下的mysql

    修改前 无法telnet 2.2.2.128 3306 打开 /etc/mysql/my.cnf 文件,找到 bind-address = 127.0.0.1 修改为 bind-address = 0 ...

  6. [转] 基于ArcGISServer实现活动地图标注

    ——王嘉彬(Esri中国上海分公司) 1.背景 1.1.主流互联网地图应用的现状 在目前主流的互联网地图应用中,如 Google Map(图 1).搜狗地图(图2),POI 兴趣点的文字标注越来越多的 ...

  7. JSHint 使用说明

    SHint介绍 翻译自www.jshint.comJSHint(注意不是jslint:))是一个由javascript社区驱动开发的用于检查javascript代码错误和问题的工具,有了他,可以使你保 ...

  8. D3 学习资源

    发现这个网站还是挺不错的:http://www.ourd3js.com/wordpress/

  9. oracle11g数据库的安装以及安装之后的配置

    1.按照正常的顺序进行安装,然后安装完成后可以对用户进行管理,(设置sys  sysmanager的口令,激活scott的用户并设置新密码) 这一步没什么好多的,关键是进行安装完成之后的配置,这个就比 ...

  10. EJDB 1.1.18 发布,嵌入式JSON数据库

    EJDB 1.1.18 增加对 MongoDB 操作符 $and 和 $or 的支持,支持 MongoDB 的 $ 推断操作符,修复了 $fields 提示的bug,提升了查询处理的性能. EJDB ...