diff --git a/404.html b/404.html index 30b0036..a6fb623 100644 --- a/404.html +++ b/404.html @@ -1,4 +1,4 @@ - c01dkit's tech blog
c01dkit/tech-blog

404 - 页面不存在捏

404 - 页面不存在捏

分支定界算法

约 6 个字 预计阅读时间不到 1 分钟

分支定界算法

约 6 个字 预计阅读时间不到 1 分钟

动态规划算法

约 6 个字 预计阅读时间不到 1 分钟

动态规划算法

约 6 个字 预计阅读时间不到 1 分钟

图算法

约 3 个字 预计阅读时间不到 1 分钟

图算法

约 3 个字 预计阅读时间不到 1 分钟

贪心算法

约 4 个字 预计阅读时间不到 1 分钟

贪心算法

约 4 个字 预计阅读时间不到 1 分钟

Index

约 1 个字 预计阅读时间不到 1 分钟

he!

Index

约 1 个字 预计阅读时间不到 1 分钟

he!

\ No newline at end of file diff --git a/algorithm-and-data-structure/data-structure/array/index.html b/algorithm-and-data-structure/data-structure/array/index.html index aeae1f9..44b75b4 100644 --- a/algorithm-and-data-structure/data-structure/array/index.html +++ b/algorithm-and-data-structure/data-structure/array/index.html @@ -1,4 +1,4 @@ - 数组 - c01dkit's tech blog

数组

约 2 个字 预计阅读时间不到 1 分钟

数组

约 2 个字 预计阅读时间不到 1 分钟

约 1 个字 预计阅读时间不到 1 分钟

约 1 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/algorithm-and-data-structure/data-structure/index.html b/algorithm-and-data-structure/data-structure/index.html index c77727b..99459b4 100644 --- a/algorithm-and-data-structure/data-structure/index.html +++ b/algorithm-and-data-structure/data-structure/index.html @@ -1,4 +1,4 @@ - Index - c01dkit's tech blog

Index

约 0 个字 预计阅读时间不到 1 分钟

Index

约 0 个字 预计阅读时间不到 1 分钟

链表

约 2 个字 预计阅读时间不到 1 分钟

链表

约 2 个字 预计阅读时间不到 1 分钟

队列

约 2 个字 预计阅读时间不到 1 分钟

队列

约 2 个字 预计阅读时间不到 1 分钟

约 1 个字 预计阅读时间不到 1 分钟

约 1 个字 预计阅读时间不到 1 分钟

约 1 个字 预计阅读时间不到 1 分钟

约 1 个字 预计阅读时间不到 1 分钟

算法与数据结构

约 81 个字 预计阅读时间不到 1 分钟

Note

有关算法与数据结构的一点笔记,先占个坑,之后慢慢填充

  • 2 0 mins
    1733369781
  • 1 0 mins
    1733369781
  • 2 0 mins
    1733369781
  • 2 0 mins
    1733369781
  • 1 0 mins
    1733369781
  • 1 0 mins
    1733369781
\ No newline at end of file diff --git a/misc-notes/environments/envs/index.html b/misc-notes/environments/envs/index.html index 7b94c9b..9b0016a 100644 --- a/misc-notes/environments/envs/index.html +++ b/misc-notes/environments/envs/index.html @@ -1,4 +1,4 @@ - 基础配置 - c01dkit's tech blog

环境配置

约 593 个字 49 行代码 预计阅读时间 7 分钟

经常遇到新系统快速配置的环境(wsl、新服务器),特此总结一下

Ubuntu更新基本环境

sudo apt update
+      

环境配置

约 593 个字 49 行代码 预计阅读时间 7 分钟

经常遇到新系统快速配置的环境(wsl、新服务器),特此总结一下

Ubuntu更新基本环境

sudo apt update
 sudo apt install curl build-essential gcc make -y
 

安装docker

按照https://docs.docker.com/engine/install/ubuntu/的说明安装即可

也可以按curl -fsSL https://get.docker.com -o get-docker.shsudo sh get-docker.sh来安装。

rust安装与更新

curl --proto '=https' --tlsv1.3 -sSf https://sh.rustup.rs | sh
 
rustup update
diff --git a/misc-notes/environments/linux-server/index.html b/misc-notes/environments/linux-server/index.html
index 95bdfb3..689bea3 100644
--- a/misc-notes/environments/linux-server/index.html
+++ b/misc-notes/environments/linux-server/index.html
@@ -1,4 +1,4 @@
- 服务器运维 - c01dkit's tech blog      

Ubuntu服务器运维

约 1216 个字 14 行代码 预计阅读时间 5 分钟

根据pid查询细节

sudo ls -lah /proc/<pid>
+      

Ubuntu服务器运维

约 1216 个字 14 行代码 预计阅读时间 5 分钟

根据pid查询细节

sudo ls -lah /proc/<pid>
 
然后根据其中的cwd找到运行目录,exe找到运行程序

在终端向程序输入字节

# 输入raw bytes
 echo -e '\x31\x32' | program
 
diff --git a/misc-notes/environments/porting/index.html b/misc-notes/environments/porting/index.html
index 94a3b01..b774289 100644
--- a/misc-notes/environments/porting/index.html
+++ b/misc-notes/environments/porting/index.html
@@ -1,4 +1,4 @@
- 端口复用 - c01dkit's tech blog      

折腾网站

约 1481 个字 49 行代码 预计阅读时间 10 分钟

端口复用方法

由于服务器安全设定,只对外开放一个22端口提供ssh连接。那么在此基础上如何提供http、https等多种服务?搜索了下可以根据流量特征用sslh简单转发一下数据包到不同的内部端口。

sslh:根据流量特征转发数据包

在root下apt install sslh后修改配置文件/etc/default/sslh

# Default options for sslh initscript
+      

折腾网站

约 1481 个字 49 行代码 预计阅读时间 10 分钟

端口复用方法

由于服务器安全设定,只对外开放一个22端口提供ssh连接。那么在此基础上如何提供http、https等多种服务?搜索了下可以根据流量特征用sslh简单转发一下数据包到不同的内部端口。

sslh:根据流量特征转发数据包

在root下apt install sslh后修改配置文件/etc/default/sslh

# Default options for sslh initscript
 # sourced by /etc/init.d/sslh
 
 # binary to use: forked (sslh) or single-thread (sslh-select) version
diff --git a/misc-notes/environments/proxy/index.html b/misc-notes/environments/proxy/index.html
index 571e7ae..066216e 100644
--- a/misc-notes/environments/proxy/index.html
+++ b/misc-notes/environments/proxy/index.html
@@ -1,4 +1,4 @@
- 代理转发 - c01dkit's tech blog      

代理转发

约 452 个字 9 行代码 预计阅读时间 2 分钟

多台电脑组局域网

可以使用zerotier,登录以后创建一个网络。然后需要组局域网的设备下载zerotier以后join上就行了。

可以参考这里这里,或者这里的一键脚本的链接配置私有planet,既能提高安全性,又能加快连接速度。简单来说,需要用ZeroTier官方代码编译自己的planet文件并替换掉zerotier客户端使用的planet,然后用ztncui这个后台管理界面配置zerotier的许可。

内网穿透

需要公网服务器,可以在阿里云租一个

一种方法是frp

另一种方法是ssh正向连接配合反向连接:

首先内网服务器开个screen运行ssh -R 127.0.0.1:1234:127.0.0.1:22 user@ip -p port连接到云服务器上。这样的话云服务器访问127.0.0.1:1234就相当于访问内网的127.0.0.1:22。然后需要连接内网的主机也开个screen运行ssh -L 127.0.0.1:2345:127.0.0.1:1234 user@ip -p port,这样的话该主机访问自己127.0.0.1:2345就相当于访问云服务器的127.0.0.1:1234。然后该主机再开一个终端,ssh user@127.0.0.1 -p 2345即可。

方便起见也可以在.ssh/config文件里用RemoteForward ip1:port1 ip2:port2LocalForward ip1:port1 ip2:port2来简化每次ssh连接都这么搞。

子网转发

希望将某端口收到的消息转发到其他主机的某一端口,可以试试socat,比如socat TCP4-LISTEN:4320,fork TCP4:10.244.55.25:80,可以把4320端口收到的TCP4数据包转发到子网10.244.55.25的80端口,配合zerotier可以实现内网对外开放端口。

即,vi /etc/systemd/system/socat.service编辑如下的socat,并systemctl enable socat.service启用开机启动,然后systemctl start socat.service。为了支持https连接,使用TCP-LISTEN/TCP。需要目标主机那边配置好ssl证书。

[Unit]
+      

代理转发

约 452 个字 9 行代码 预计阅读时间 2 分钟

多台电脑组局域网

可以使用zerotier,登录以后创建一个网络。然后需要组局域网的设备下载zerotier以后join上就行了。

可以参考这里这里,或者这里的一键脚本的链接配置私有planet,既能提高安全性,又能加快连接速度。简单来说,需要用ZeroTier官方代码编译自己的planet文件并替换掉zerotier客户端使用的planet,然后用ztncui这个后台管理界面配置zerotier的许可。

内网穿透

需要公网服务器,可以在阿里云租一个

一种方法是frp

另一种方法是ssh正向连接配合反向连接:

首先内网服务器开个screen运行ssh -R 127.0.0.1:1234:127.0.0.1:22 user@ip -p port连接到云服务器上。这样的话云服务器访问127.0.0.1:1234就相当于访问内网的127.0.0.1:22。然后需要连接内网的主机也开个screen运行ssh -L 127.0.0.1:2345:127.0.0.1:1234 user@ip -p port,这样的话该主机访问自己127.0.0.1:2345就相当于访问云服务器的127.0.0.1:1234。然后该主机再开一个终端,ssh user@127.0.0.1 -p 2345即可。

方便起见也可以在.ssh/config文件里用RemoteForward ip1:port1 ip2:port2LocalForward ip1:port1 ip2:port2来简化每次ssh连接都这么搞。

子网转发

希望将某端口收到的消息转发到其他主机的某一端口,可以试试socat,比如socat TCP4-LISTEN:4320,fork TCP4:10.244.55.25:80,可以把4320端口收到的TCP4数据包转发到子网10.244.55.25的80端口,配合zerotier可以实现内网对外开放端口。

即,vi /etc/systemd/system/socat.service编辑如下的socat,并systemctl enable socat.service启用开机启动,然后systemctl start socat.service。为了支持https连接,使用TCP-LISTEN/TCP。需要目标主机那边配置好ssl证书。

[Unit]
 Description=port forward 4320
 
 [Service]
diff --git a/misc-notes/index.html b/misc-notes/index.html
index 1076f2c..a9d7076 100644
--- a/misc-notes/index.html
+++ b/misc-notes/index.html
@@ -1,4 +1,4 @@
- Index - c01dkit's tech blog      

Index

约 0 个字 预计阅读时间不到 1 分钟

Index

约 0 个字 预计阅读时间不到 1 分钟

autoconf学习笔记

约 292 个字 85 行代码 预计阅读时间 9 分钟

自己开发软件时,生成规范的configure等文件。可参考https://www.cnblogs.com/klausage/p/14163844.html

不分目录结构

编写Makefile.am文件,比如:

bin_PROGRAMS=helloworld
+      

autoconf学习笔记

约 292 个字 85 行代码 预计阅读时间 9 分钟

自己开发软件时,生成规范的configure等文件。可参考https://www.cnblogs.com/klausage/p/14163844.html

不分目录结构

编写Makefile.am文件,比如:

bin_PROGRAMS=helloworld
 helloworld_SOURCES=helloworld.c
 
  • bin_PROGRAMS用于给项目起名,比如X,那么之后的X_SOURCES则用来指定使用的源文件

执行autoscan,生成configure.scan,并修改其中的AC_INIT、AM_INIT_AUTOMAKE,重命名文件为configure.ac,比如:

#                                               -*- Autoconf -*-
 # Process this file with autoconf to produce a configure script.
diff --git a/misc-notes/software-kits/docker/index.html b/misc-notes/software-kits/docker/index.html
index 1382054..ac7de72 100644
--- a/misc-notes/software-kits/docker/index.html
+++ b/misc-notes/software-kits/docker/index.html
@@ -1,4 +1,4 @@
- Docker - c01dkit's tech blog      

Docker使用笔记

约 722 个字 11 行代码 预计阅读时间 4 分钟

安装docker

按照https://docs.docker.com/engine/install/ubuntu/的说明安装即可

也可以按curl -fsSL https://get.docker.com -o get-docker.shsudo sh get-docker.sh来安装。

设置docker使用镜像仓库

docker默认从官网拉取镜像,可能由于墙而拉不到。可以考虑使用阿里提供的镜像服务,参考https://zhuanlan.zhihu.com/p/347643668

考虑到国内似乎把docker镜像下架了,还是直接修改docker代理吧。

先创建目录mkdir /etc/systemd/system/docker.service.d,再创建文件/etc/systemd/system/docker.service.d/http-proxy.conf,再往里面添加代理:

[Service]
+      

Docker使用笔记

约 722 个字 11 行代码 预计阅读时间 4 分钟

安装docker

按照https://docs.docker.com/engine/install/ubuntu/的说明安装即可

也可以按curl -fsSL https://get.docker.com -o get-docker.shsudo sh get-docker.sh来安装。

设置docker使用镜像仓库

docker默认从官网拉取镜像,可能由于墙而拉不到。可以考虑使用阿里提供的镜像服务,参考https://zhuanlan.zhihu.com/p/347643668

考虑到国内似乎把docker镜像下架了,还是直接修改docker代理吧。

先创建目录mkdir /etc/systemd/system/docker.service.d,再创建文件/etc/systemd/system/docker.service.d/http-proxy.conf,再往里面添加代理:

[Service]
 Environment="HTTP_PROXY=http://proxy.example.com:80/"
 Environment="HTTPS_PROXY=http://proxy.example.com:80/"
 Environment="NO_PROXY=localhost,127.0.0.0/8,docker-registry.somecorporation.com" #可选。如果使用本地镜像仓库。
diff --git a/misc-notes/software-kits/git/index.html b/misc-notes/software-kits/git/index.html
index dc7c622..fa743a1 100644
--- a/misc-notes/software-kits/git/index.html
+++ b/misc-notes/software-kits/git/index.html
@@ -1,4 +1,4 @@
- Git - c01dkit's tech blog      

Git学习笔记

约 1937 个字 3 行代码 预计阅读时间 7 分钟

将本地已有仓库推送至Github的新建仓库中

默认以下条件均成立:

  • 已在github上创建同名空仓库(不同名也行)
  • 已配置好ssh密钥
  • 已建立好本地仓库(git init +git add . +git commit -m "comments")
  • 本地仓库为clean状态(使用git status查看)
  1. 进入本地git仓库,使用git remote add origin git@github.com:xxx(仓库网站比如github提供的ssh地址)
  2. 使用git push -u origin master向远程仓库提交代码(后来听说github默认名改成main了?)

强制推送可以再加个--force参数

添加.gitignore文件以不追踪文件

初次向github提交代码前,在本地工作目录下创建.gitignore文件,里面直接写上不想追踪的文件名和文件夹名即可。(文件名不需要补全路径)

撤回add

使用git add .可以直接把当前目录都add进暂存区,对于不慎添加的内容可以使用git rm --cached <file>来撤回add。可以使用git rm -r --cached .来撤回git add . 。(使用git status可以查看暂存区,里面也有提示怎么撤回)

配置git账号并加入github项目

  1. 使用git config --global user.name "<yourname>"设置用户名
  2. 使用git config --global user.email "<email>"设置邮箱
  3. 使用ssh-keygen -t rsa -C "<comments>"生成密钥对,然后一路回车直到生成结束(也可以提示添加passwd phrase,这样的话如果使用ssh-add添加时会要求输入这个密码防止被别人滥用。注意相同的passwd phrase不会生成相同的密钥对)
  4. 在上一步过程中默认的路径(比如~/.ssh)找到id_rsa.pub文件,拷贝其全部内容
  5. 打开github,右上角头像,settings,左侧的SSH and GPG keys,然后给SSH添加这个公钥即可

ed25519似乎比默认的rsa更安全、计算更快、密钥更短,可以使用

有时需要指定密钥,比如不使用默认的密钥文件名。此时可以先eval $(ssh-agent -s)启用agent,然后ssh-add <private keyfile> 来添加密钥。ssh-add -l可以查看添加的密钥。

或者可以把密钥在~/.ssh/config文件里指定一下,就可以省去ssh-agent的操作,比如

Host github.com
+      

Git学习笔记

约 1937 个字 3 行代码 预计阅读时间 7 分钟

将本地已有仓库推送至Github的新建仓库中

默认以下条件均成立:

  • 已在github上创建同名空仓库(不同名也行)
  • 已配置好ssh密钥
  • 已建立好本地仓库(git init +git add . +git commit -m "comments")
  • 本地仓库为clean状态(使用git status查看)
  1. 进入本地git仓库,使用git remote add origin git@github.com:xxx(仓库网站比如github提供的ssh地址)
  2. 使用git push -u origin master向远程仓库提交代码(后来听说github默认名改成main了?)

强制推送可以再加个--force参数

添加.gitignore文件以不追踪文件

初次向github提交代码前,在本地工作目录下创建.gitignore文件,里面直接写上不想追踪的文件名和文件夹名即可。(文件名不需要补全路径)

撤回add

使用git add .可以直接把当前目录都add进暂存区,对于不慎添加的内容可以使用git rm --cached <file>来撤回add。可以使用git rm -r --cached .来撤回git add . 。(使用git status可以查看暂存区,里面也有提示怎么撤回)

配置git账号并加入github项目

  1. 使用git config --global user.name "<yourname>"设置用户名
  2. 使用git config --global user.email "<email>"设置邮箱
  3. 使用ssh-keygen -t rsa -C "<comments>"生成密钥对,然后一路回车直到生成结束(也可以提示添加passwd phrase,这样的话如果使用ssh-add添加时会要求输入这个密码防止被别人滥用。注意相同的passwd phrase不会生成相同的密钥对)
  4. 在上一步过程中默认的路径(比如~/.ssh)找到id_rsa.pub文件,拷贝其全部内容
  5. 打开github,右上角头像,settings,左侧的SSH and GPG keys,然后给SSH添加这个公钥即可

ed25519似乎比默认的rsa更安全、计算更快、密钥更短,可以使用

有时需要指定密钥,比如不使用默认的密钥文件名。此时可以先eval $(ssh-agent -s)启用agent,然后ssh-add <private keyfile> 来添加密钥。ssh-add -l可以查看添加的密钥。

或者可以把密钥在~/.ssh/config文件里指定一下,就可以省去ssh-agent的操作,比如

Host github.com
     HostName github.com
     IdentityFile ~/.ssh/id_ed25519_user_github
 

有的时候git进行push到私仓时会出现卡机的问题,不确定是什么原因,如果remote repo使用的是git@xxx的url的话,可以试试改成https的链接;还不行的话可以试试git config的proxy,设置或清空。

放弃对文件的跟踪

与他人合作项目时,有时需要做一些本地适配,但是不想妨碍其他人,可以添加到.gitignore。但对于已经处于跟踪状态的文件来说后添进.gitignore是无效的。因此可以先将文件移出跟踪态,然后再加进.gitignore里。如下:git rm -r --cached <file/dir>其中-r表示递归。也可以加-n表示伪放弃跟踪(用于预览会放弃对哪些文件的追踪)

更换远程仓库

有的时候从官方仓库git clone下代码,本地拷贝一份、各种魔改并上传到自己的私仓。又由于windows、linux环境不同,想把原来的代码更新成自己的私仓,所以需要换一下远程仓库。

  1. 首先取消原来的远程分支跟踪git remote rm <remote repo name>
  2. 然后添加自己的仓库作为远程git remote add <remote repo name> <repo url>

好像也可以直接更换远程仓库:git remote set-url <remote repro name> <repo url>

这里的<remote repo name>是自己取的仓库名,之后的操作可以用它来指定对象。可以随便取,比如常见的origin。

子模块的下载

有的时候一个代码仓库拿其他仓库来当做子模块,在github上这些模块是图中的表示形式。git仓库里也会有.gitmodules文件来说明这些子模块。当clone主仓库时,这些子模块不会跟着下载下来。

初次部署时,在主仓库目录下里使用git submodule update --init --recursive来从.gitmodules字clone子模块。

如果子模块被别的开发者更新了,可以进到子模块中然后git pull

如果希望添加某个仓库作为子模块,使用git submodule add <repo url>来下载子模块并更新.gitmodules文件

自己的项目需要对其他项目进行修改

如果自己的项目用到别的项目,需要对其中一些代码进行修改,而不需要把在上传github时把整个项目全部放到自己的项目下,可以先用submodule添加子模块,然后直接修改代码,并在其项目下用git diff <commit id> > <file.patch>生成一个diff文件。把diff文件放到自己的项目里,再上传到github上。其中commit id是第三方项目的commit,也就是这个submodule下载时的commit id,可以通过git log找到。

如果直接用git diff > <file.patch>,会输出未加入暂存的修改和最近一次暂存/commit的diff文件。

其他人使用时,就先把第三方项目获取下来,然后git apply <file.patch>即可。撤回补丁使用git apply -R <file.patch>

不同版本多人合作与分支使用

最近在跑fuzzer,合作时有时需要切换不同的测试目标,每个测试目标都有自己的一大堆配套设置。大家都在主分支删改太麻烦而且很乱,所以需要针对每个测试目标设置不同的branch。

可以使用git branch -a查看所有分支。其中前面带*的是当前branch。

新建分支时使用 git checkout -b <branch name> 相当于先git branch <branch name> 创建了一个新的分支,然后git checkout <branch name>切换到那个分支。

在新的分支commit后,使用git push -u <remote repo name> <local branch name>:<remote branch name>可以将自己的这个分支推送到远程仓库。其中:

  • -u表示记住当前设定,之后在这一分支上push时,简单使用git push就会推送,不需要再敲这么长了。
  • origin 是之前git remote add origin 设定的远程主机名称,需要和实际设定一样。因为大家使用origin是在太普遍了,所以这里没有用<remote host name>来表示,意会即可。
  • local branch name和remote branch name一般情况是相同的。会在远程新建remote branch name

如果需要删除远程分支,可以简单地推送空分支:git push origin :<remote branch name>。这里本地分支名留空了。也可以使用专门的删除方式:git push origin --delete <remote branch name>

如果需要删除本地分支,使用git branch -d <local branch name>

合并分支时,先切换到需要接收改动的分支上,然后git merge <new branch name>,即可将new branch的改动更新到当前分支上。new branch的内容是不变的。

拉取远程分支到本地,而不影响本地分支:git fetch <remote repo name> <remote branch name>:<local branch name>会将远程仓库的分支保存在本地对应分支下。

可以用git fetch --all拉取所有远程分支,如果没有效果,注意检查remote.origin.fetch的设置:git config --get remote.origin.fetch,如果是+refs/heads/master:refs/remotes/origin/master,则表示只拉master分支。可以修改成拉取所有分支:git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"

Github debug合集

某种东西真的神烦,科研需要下载的仓库代码经常莫名其妙下载不了,写的代码上传补上去,build个docker慢的要死,第三方包拉取不到……浪费很多时间在因为网络连接不了导致的各种bug上,有效科研时间白白被消耗,真的很xx。

Git clone报错gnutls_handshake() failed: The TLS connection was non-properly terminated.

一种做法是设置或者取消设置http.proxy和https.proxy

另一种做法是直接取消SSL校验,虽然粗暴了点:git config http.sslVerify false

OpenSSH阅读笔记

约 164 个字 5 行代码 预计阅读时间 1 分钟

准备工作

(以下均在wsl的root用户) ubuntu系统,先预装下环境:

apt install build-essential autoconf zlib1g-dev libssl-dev
+      

OpenSSH阅读笔记

约 164 个字 5 行代码 预计阅读时间 1 分钟

准备工作

(以下均在wsl的root用户) ubuntu系统,先预装下环境:

apt install build-essential autoconf zlib1g-dev libssl-dev
 

下载源码,直接从Github链接下载zip到本地解压,也可以用git clone:

git clone --depth 1 https://github.com/openssh/openssh-portable.git
 

为了防止之后make install出的文件覆盖系统自己的ssh,这里指定configure将之后编译出的文件放到项目的/output文件夹下。按readme的Building from git的方法,进入openssh所在目录后,运行:

autoreconf
 ./configure --prefix=`pwd`/output
diff --git a/misc-notes/software-kits/tech-sslh/index.html b/misc-notes/software-kits/tech-sslh/index.html
index deb2240..55fb6f8 100644
--- a/misc-notes/software-kits/tech-sslh/index.html
+++ b/misc-notes/software-kits/tech-sslh/index.html
@@ -1,4 +1,4 @@
- sslh - c01dkit's tech blog      

sslh 阅读笔记

约 1131 个字 99 行代码 预计阅读时间 14 分钟

最近在读sslh的源码,感觉还是比较有意思的。之前在端口复用里面简单提了下sslh的用法,但是在实践中踩了不少坑,所以把源码拿来读一读,看看内部的结构。

sslh似乎是使用第一个数据包保存的协议信息,为客户端与服务器对应服务建立连接。后续数据包不再需要检查协议了。

便捷上手

apt install sslh # 但最好还是从源码make install,用最新版本;参考仓库的INSTALL安装对应的C库
+      

sslh 阅读笔记

约 1131 个字 99 行代码 预计阅读时间 14 分钟

最近在读sslh的源码,感觉还是比较有意思的。之前在端口复用里面简单提了下sslh的用法,但是在实践中踩了不少坑,所以把源码拿来读一读,看看内部的结构。

sslh似乎是使用第一个数据包保存的协议信息,为客户端与服务器对应服务建立连接。后续数据包不再需要检查协议了。

便捷上手

apt install sslh # 但最好还是从源码make install,用最新版本;参考仓库的INSTALL安装对应的C库
 vi /etc/default/sslh
 systemctl start sslh
 

似乎cfg文件里和command line会有冲突。所以commandline用-F /etc/sslh/sslh.cfg(没有则新建一个)指定的配置文件中,不要有和command重复的内容。只放protocols差不多就得了。比较好用的是正则和tls中根据alpn和sni来匹配。

下面是完整的配置文件的一个例子,如果数据包包含”OK1”或者”OK2”,则会被转发到127.0.0.1:1234。其中的name字段表示这条协议在sslh启动后怎么配置,常见的比如regexsshtlshttp

注意,最后一条协议的分号后面不加逗号。

protocols:
diff --git a/misc-notes/software-kits/try-chatgpt/index.html b/misc-notes/software-kits/try-chatgpt/index.html
index 04e44a1..ae4cbf9 100644
--- a/misc-notes/software-kits/try-chatgpt/index.html
+++ b/misc-notes/software-kits/try-chatgpt/index.html
@@ -1,4 +1,4 @@
- ChatGPT - c01dkit's tech blog      

ChatGPT来帮忙

约 1574 个字 3 行代码 预计阅读时间 6 分钟

网络站点打包下载

linux用哪个命令可以把一个网址以及其所依赖的js和css等等文件自动下载下来?

在Linux中,你可以使用 wget 命令来自动下载一个网站及其依赖的资源文件(如JS和CSS等)。

下面是一个示例命令:

wget --recursive --no-clobber --page-requisites --html-extension --convert-links --restrict-file-names=windows --domains website.com --no-parent http://website.com
+      

ChatGPT来帮忙

约 1574 个字 3 行代码 预计阅读时间 6 分钟

网络站点打包下载

linux用哪个命令可以把一个网址以及其所依赖的js和css等等文件自动下载下来?

在Linux中,你可以使用 wget 命令来自动下载一个网站及其依赖的资源文件(如JS和CSS等)。

下面是一个示例命令:

wget --recursive --no-clobber --page-requisites --html-extension --convert-links --restrict-file-names=windows --domains website.com --no-parent http://website.com
 
该命令使用了多个选项,其中一些选项的含义如下:

–recursive: 下载网站的所有链接。 –no-clobber: 不会重复下载已经存在的文件。 –page-requisites: 下载所有页面的资源(如图像,音频和视频)。 –html-extension: 将所有HTML文件扩展名添加为 .html。 –convert-links: 将所有链接转换为本地链接。 –restrict-file-names=windows: 避免使用 Linux 不支持的文件名字符。 –domains website.com: 限制下载的域名范围。 –no-parent: 不会下载父级链接(有助于防止无限递归)。

你可以根据自己的需要修改这些选项以满足特定的要求。

用这条命令被服务器发现恶意下载,被给403 forbidden了怎么办?

如果你使用的命令被服务器认为是恶意下载,并且被服务器拒绝访问,那么你可以考虑以下一些方法来解决这个问题:

修改下载速度:有些服务器可能会限制下载速度,如果你下载的太快,就会被认为是攻击。你可以尝试使用 –limit-rate 选项来限制下载速度,例如:

wget --limit-rate=200k http://example.com
 

修改下载并发数:类似于速度限制,一些服务器也会限制同时进行的下载数。你可以尝试使用 –tries 和 –wait 选项来限制并发下载数,例如:

wget --tries=10 --wait=5 http://example.com
 
添加 User-Agent:有些服务器可能会检查 User-Agent,如果 User-Agent 被认为是恶意的,那么你的请求也会被拒绝。你可以尝试使用 –user-agent 选项来设置 User-Agent,例如:

wget --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3" http://example.com
diff --git a/programming-languages/c/index.html b/programming-languages/c/index.html
index c714d5e..109fc34 100644
--- a/programming-languages/c/index.html
+++ b/programming-languages/c/index.html
@@ -1,4 +1,4 @@
- C - c01dkit's tech blog      

C语言

约 386 个字 30 行代码 预计阅读时间 4 分钟

根据结构体成员取结构体首地址

member_address - &(((TYPE *)0)->member);
+      

C语言

约 386 个字 30 行代码 预计阅读时间 4 分钟

根据结构体成员取结构体首地址

member_address - &(((TYPE *)0)->member);
 

后半部分看似会解引用0地址而crash,但编译器会优化为直接计算member的offset。参见kernel代码常用的container_of。

动态链接库

编译动态链接库本身

使用gcc编译出动态链接库:

gcc <source C file> -shared -fPIC -o lib<source>.so
 

编译原项目时指定动态链接库

使用-l指定加载链接库,注意去掉库文件的lib开头和.so结尾。编译时,注意把库放在整个命令的结尾,否则可能提示库函数未定义。

比如gcc main.c -lcapstone不会报错,gcc -lcapstone main.c会提示报错。(假设这里main.c调用了capstone的库函数)

如果动态链接库不在默认的系统库中,可以添加-L来指定动态链接库的保存位置。

运行项目时加载动态链接库

即便编译成功,运行可能报错。搜索顺序为:

  1. 在编译时添加-Wl,-rpath=xxx来指定运行时所需的动态库文件
  2. 在环境变量LD_LIBRARY_PATH指定的目录中搜索
  3. /etc/ld.so.conf给出的目录中搜索
  4. 在默认的搜索路径/lib/lib64/usrlib/usrlib64等搜索

赋值

初始化数组,可以连续赋值

int arr[10] = {
     [0]       = 1,
@@ -130,6 +130,6 @@
   var target = document.getElementById(location.hash.slice(1))
   if (target && target.name)
     target.checked = target.name.startsWith("__tabbed_")
- 
\ No newline at end of file diff --git a/programming-languages/code-gracely/index.html b/programming-languages/code-gracely/index.html index 65f6bbc..fbf1135 100644 --- a/programming-languages/code-gracely/index.html +++ b/programming-languages/code-gracely/index.html @@ -1,4 +1,4 @@ - 优雅编程 - c01dkit's tech blog

优雅编程

约 1414 个字 预计阅读时间 5 分钟

程序变量

  • 最好在声明的同时初始化,尤其是避免仅初始化对象的部分成员
  • 尽可能地缩短变量的生命周期与跨度(即在使用前先初始化、多定义变量)
  • 不要在多个代码片段之间使用temp等不明意义的命名,这样会使不相关的代码看起来相关
  • 警惕隐式含义,比如某变量为正数时为整数类型,负数时表示隐含的“出错”(即隐含布尔类型),改用多个变量
  • 确保所有声明的变量都使用过
  • 变量名称要描述“什么”,而不是“怎么”,要具象
  • 变量名称长度在8-20个字母比较适宜
  • Total、Sum、Max、Record、String、Pointer等等限定词要加到名字最后
  • i、j、k等约定速成的变量名适用于简单的循环,不要用于任何简单循环的下标循环之外的任何场合
  • 多个复杂循环嵌套时,最好不要使用i、j、k
  • 为状态变量起一个比flag更好的名字,比如不使用statusFlag,而是characterType(更加具体描述是什么status)
  • 使用done、error、found、ok等为布尔变量赋值
  • 为布尔变量赋予隐含真假意义的名字,比如sourceFileAvailable、sourceFileFound
  • 使用肯定的布尔变量名,不要包含“not”之类的否定含义
  • 如果枚举类型变量不需要指定域,那么使用类似COLOR_xxx的前缀来指定类别会比较好

程序优化方法

优化需要通过大量测试来验证一致性、性能,因为并非所有优化都是正确或必要的。从重构程序执行流的角度来讲,优化并不是灵丹妙药,并在不同语言、不同编译器、不同环境、不同任务中表现出巨大的差异。以下的优化方法均仅供参考。

利用短路与哨兵

  • 将出现频率高的情况放在优先执行的位置
  • 循环中,搜索到目标后立即退出循环
  • 循环搜索时,也可以将搜索对象放在数组最后(额外空间),最后检查下标。(本质上是保证不会越界搜索,且保证循环一定正确结束)

优化计算效率

  • 程序执行前计算结果,通过常量保存、硬编码、文件保存的方法来避免重复计算
  • 尽量减少循环体内的计算工作,可以在之前计算完毕并保存,之后引用
  • 公共子表达式应当保存在变量里
  • 适当将乘法重写为加法、幂重写为乘法、整数代替浮点数、单精度代替双精度、移位操作代替乘除2、三角恒等式代替三角函数
  • 尽量减少数组维度与数组引用
  • 多重循环时,将循环次数少的放外层

使用低级语言重写代码

  1. 使用高级语言完成程序编写
  2. 进行测试,验证正确性
  3. 进行程序分析,确定热点代码
  4. 对热点代码使用低级语言改写

设计恰当的执行控制流

循环

  • 循环层数最好不要超过三层
  • 短循环可以多使用break、continue等控制,长循环尽量保证唯一出口
  • 循环附近不要写重复的代码(修改需要同步修改多处,不便维护)
  • for适合与“数量”有关的循环,且不要在内部修改下标;while适合与“条件”有关的循环
  • 循环体应当自成子程序,循环条件应当清晰易读
  • 多使用for循环,但不要把与循环无关的语句(比如初始化一个不用于循环的变量)放在循环头
  • 不要写空循环,将空循环改写成while循环
  • 如果一个循环可以做两件事情,把它们拆成两个循环,除非注明在性能上有所提高
  • 不要将循环下标作为结果返回。如果需要使用,可以在循环开始前定义新的变量,然后在循环内部对这一变量进行赋值

建表,以提高代码质量

用查表法替换繁琐的if-else判断

使用大量if-else的坏处:

  • 不易阅读
  • 代码重复度高,无意义
  • 对于复杂情况,容易漏条件
  • 判断逻辑硬编码在代码中,维护不便

使用查表法的好处:

  • 易读
  • 代码简洁且高效
  • 不会漏掉条件
  • 可以将表放在外部文件或者统一放在一起,便于维护;可以在不改变程序的情况下修正运行结果

用法:将要判断的各个参数作为表的维度,将判断结果作为表索引后的结果。

用索引表替换数据表

稀疏的数据表在存储对齐的情况下会浪费大量空间。与之相比,采用索引表可以降低空间浪费量(仍然会产生浪费)。为了进一步减少索引表空间,可以使用阶梯索引表,根据数据的范围(而不是具体的数据值)进行建索引,比如根据百分制成绩计算绩点,建立相应的data-to-key函数,放在数组中。

用结果表替换数学计算结果

考虑到系统函数的精确性,计算速度可能较慢。可以预先手动算出一些数据并建表,计算时直接查表即可,大大提高程序性能。

优雅编程

约 1414 个字 预计阅读时间 5 分钟

程序变量

  • 最好在声明的同时初始化,尤其是避免仅初始化对象的部分成员
  • 尽可能地缩短变量的生命周期与跨度(即在使用前先初始化、多定义变量)
  • 不要在多个代码片段之间使用temp等不明意义的命名,这样会使不相关的代码看起来相关
  • 警惕隐式含义,比如某变量为正数时为整数类型,负数时表示隐含的“出错”(即隐含布尔类型),改用多个变量
  • 确保所有声明的变量都使用过
  • 变量名称要描述“什么”,而不是“怎么”,要具象
  • 变量名称长度在8-20个字母比较适宜
  • Total、Sum、Max、Record、String、Pointer等等限定词要加到名字最后
  • i、j、k等约定速成的变量名适用于简单的循环,不要用于任何简单循环的下标循环之外的任何场合
  • 多个复杂循环嵌套时,最好不要使用i、j、k
  • 为状态变量起一个比flag更好的名字,比如不使用statusFlag,而是characterType(更加具体描述是什么status)
  • 使用done、error、found、ok等为布尔变量赋值
  • 为布尔变量赋予隐含真假意义的名字,比如sourceFileAvailable、sourceFileFound
  • 使用肯定的布尔变量名,不要包含“not”之类的否定含义
  • 如果枚举类型变量不需要指定域,那么使用类似COLOR_xxx的前缀来指定类别会比较好

程序优化方法

优化需要通过大量测试来验证一致性、性能,因为并非所有优化都是正确或必要的。从重构程序执行流的角度来讲,优化并不是灵丹妙药,并在不同语言、不同编译器、不同环境、不同任务中表现出巨大的差异。以下的优化方法均仅供参考。

利用短路与哨兵

  • 将出现频率高的情况放在优先执行的位置
  • 循环中,搜索到目标后立即退出循环
  • 循环搜索时,也可以将搜索对象放在数组最后(额外空间),最后检查下标。(本质上是保证不会越界搜索,且保证循环一定正确结束)

优化计算效率

  • 程序执行前计算结果,通过常量保存、硬编码、文件保存的方法来避免重复计算
  • 尽量减少循环体内的计算工作,可以在之前计算完毕并保存,之后引用
  • 公共子表达式应当保存在变量里
  • 适当将乘法重写为加法、幂重写为乘法、整数代替浮点数、单精度代替双精度、移位操作代替乘除2、三角恒等式代替三角函数
  • 尽量减少数组维度与数组引用
  • 多重循环时,将循环次数少的放外层

使用低级语言重写代码

  1. 使用高级语言完成程序编写
  2. 进行测试,验证正确性
  3. 进行程序分析,确定热点代码
  4. 对热点代码使用低级语言改写

设计恰当的执行控制流

循环

  • 循环层数最好不要超过三层
  • 短循环可以多使用break、continue等控制,长循环尽量保证唯一出口
  • 循环附近不要写重复的代码(修改需要同步修改多处,不便维护)
  • for适合与“数量”有关的循环,且不要在内部修改下标;while适合与“条件”有关的循环
  • 循环体应当自成子程序,循环条件应当清晰易读
  • 多使用for循环,但不要把与循环无关的语句(比如初始化一个不用于循环的变量)放在循环头
  • 不要写空循环,将空循环改写成while循环
  • 如果一个循环可以做两件事情,把它们拆成两个循环,除非注明在性能上有所提高
  • 不要将循环下标作为结果返回。如果需要使用,可以在循环开始前定义新的变量,然后在循环内部对这一变量进行赋值

建表,以提高代码质量

用查表法替换繁琐的if-else判断

使用大量if-else的坏处:

  • 不易阅读
  • 代码重复度高,无意义
  • 对于复杂情况,容易漏条件
  • 判断逻辑硬编码在代码中,维护不便

使用查表法的好处:

  • 易读
  • 代码简洁且高效
  • 不会漏掉条件
  • 可以将表放在外部文件或者统一放在一起,便于维护;可以在不改变程序的情况下修正运行结果

用法:将要判断的各个参数作为表的维度,将判断结果作为表索引后的结果。

用索引表替换数据表

稀疏的数据表在存储对齐的情况下会浪费大量空间。与之相比,采用索引表可以降低空间浪费量(仍然会产生浪费)。为了进一步减少索引表空间,可以使用阶梯索引表,根据数据的范围(而不是具体的数据值)进行建索引,比如根据百分制成绩计算绩点,建立相应的data-to-key函数,放在数组中。

用结果表替换数学计算结果

考虑到系统函数的精确性,计算速度可能较慢。可以预先手动算出一些数据并建表,计算时直接查表即可,大大提高程序性能。

\ No newline at end of file diff --git a/programming-languages/cpp/index.html b/programming-languages/cpp/index.html index 715e54b..0fc7980 100644 --- a/programming-languages/cpp/index.html +++ b/programming-languages/cpp/index.html @@ -1,4 +1,4 @@ - C++ - c01dkit's tech blog

C++

约 1253 个字 196 行代码 预计阅读时间 24 分钟

STL与常用数据类型

string

可以直接使用==判断string字符串是否相等、+来进行字符串拼接。

vector动态数组

vector 动态数组可以随机访问,其大小由系统自动管理。

#include<vector>
+      

C++

约 1253 个字 196 行代码 预计阅读时间 24 分钟

STL与常用数据类型

string

可以直接使用==判断string字符串是否相等、+来进行字符串拼接。

vector动态数组

vector 动态数组可以随机访问,其大小由系统自动管理。

#include<vector>
 
 // 声明与初始化
 std::vector<int> vec1;
diff --git a/programming-languages/crawler/index.html b/programming-languages/crawler/index.html
index 1cba398..09850a3 100644
--- a/programming-languages/crawler/index.html
+++ b/programming-languages/crawler/index.html
@@ -1,4 +1,4 @@
- python爬虫 - c01dkit's tech blog      

爬虫模板

约 142 个字 156 行代码 预计阅读时间 16 分钟

Scrapy

也可以看这里的介绍

加国内代理

针对个别网站锁ip,可以考虑整个代理

import base64
+      

爬虫模板

约 142 个字 156 行代码 预计阅读时间 16 分钟

Scrapy

也可以看这里的介绍

加国内代理

针对个别网站锁ip,可以考虑整个代理

import base64
 username = 'xxxxx'
 passwd = 'xxxxx'
 proxy_ip = 'xxxx.kdltps.com'
diff --git a/programming-languages/go/index.html b/programming-languages/go/index.html
index 1e7c85a..ab4a823 100644
--- a/programming-languages/go/index.html
+++ b/programming-languages/go/index.html
@@ -1,4 +1,4 @@
- Go - c01dkit's tech blog      

go

约 66 个字 14 行代码 预计阅读时间 2 分钟

go环境配置

  1. https://go.dev/dl/下载Archive的包,解压缩(比如到~/.local),添加其中的bin目录到PATH路径
  2. 国内使用时设置代理
go env -w GO111MODULE=on
+      

go

约 66 个字 14 行代码 预计阅读时间 2 分钟

go环境配置

  1. https://go.dev/dl/下载Archive的包,解压缩(比如到~/.local),添加其中的bin目录到PATH路径
  2. 国内使用时设置代理
go env -w GO111MODULE=on
 go env -w  GOPROXY=https://goproxy.cn
 

创建工程

工程保存在xxx/go/src/xxx下,并将GOPATH=xxx/go加到环境变量中

快速入门

package main
 import (
diff --git a/programming-languages/index.html b/programming-languages/index.html
index 2d0f80d..35285bf 100644
--- a/programming-languages/index.html
+++ b/programming-languages/index.html
@@ -1,4 +1,4 @@
- Index - c01dkit's tech blog     

编程语言

约 52 个字 预计阅读时间不到 1 分钟

Note

有关各类编程语言的一点学习笔记,不定期更新

  • 1253 196 7 mins
    1733387163
  • 386 30 2 mins
    1733369781
  • 66 14 0 mins
    1733369781
  • 108 0 mins
    1733369781
  • 786 242 6 mins
    1733369781

Java

约 108 个字 预计阅读时间不到 1 分钟

Java环境配置

https://www.oracle.com/java/technologies/downloads/下载对应系统的包。Linux选择Compressed Archive,解压缩以后配置下path;Windows可以用MSI Installer。对应的源码在lib/src.zip中。

Java源码架构理解

核心代码、主要功能在java.base/java目录下,其中包含了io、lang、util等多个关键模块。

Java里有哪些数据结构类型?如何实现的?

Java中常见的数据类型比如Set、Array、

Java

约 108 个字 预计阅读时间不到 1 分钟

Java环境配置

https://www.oracle.com/java/technologies/downloads/下载对应系统的包。Linux选择Compressed Archive,解压缩以后配置下path;Windows可以用MSI Installer。对应的源码在lib/src.zip中。

Java源码架构理解

核心代码、主要功能在java.base/java目录下,其中包含了io、lang、util等多个关键模块。

Java里有哪些数据结构类型?如何实现的?

Java中常见的数据类型比如Set、Array、

Python

约 786 个字 242 行代码 预计阅读时间 27 分钟

一些小点

  • 对字符串去除空白符时,用split()不加参数。注意split(’ ‘)按空格分隔时,如果存在连续的空格,那么结果里会有空字符串’‘。

获取未知对象的所有属性

obj.__dir__() 或者dir(obj)

  • 解析命令行参数:argparse
  • 日志输出:logging
  • 处理配置文件:yaml、json
  • 进度条输出:tqdm
  • python调用C库:ctypes.cdll.LoadLibrary
  • 设定计时信号:signal.alarm

参数解析:argparse

根据用户传参而执行不同的功能,又分多个层次。比如pip3命令,可以有pip3 install和pip3 freeze等等,对于每一个子解析又有进一步的参数,比如pip3 install –upgrade, pip3 install –force-reinstall等等。

import argparse
+      

Python

约 786 个字 242 行代码 预计阅读时间 27 分钟

一些小点

  • 对字符串去除空白符时,用split()不加参数。注意split(’ ‘)按空格分隔时,如果存在连续的空格,那么结果里会有空字符串’‘。

获取未知对象的所有属性

obj.__dir__() 或者dir(obj)

  • 解析命令行参数:argparse
  • 日志输出:logging
  • 处理配置文件:yaml、json
  • 进度条输出:tqdm
  • python调用C库:ctypes.cdll.LoadLibrary
  • 设定计时信号:signal.alarm

参数解析:argparse

根据用户传参而执行不同的功能,又分多个层次。比如pip3命令,可以有pip3 install和pip3 freeze等等,对于每一个子解析又有进一步的参数,比如pip3 install –upgrade, pip3 install –force-reinstall等等。

import argparse
 
 def populate_parser(parser):
     parser.add_argument('input_file', type=str, help="Path to the file containing the mutated input to load")
diff --git a/researching-is-living/general/interesting-articles/index.html b/researching-is-living/general/interesting-articles/index.html
index e12015c..64e99df 100644
--- a/researching-is-living/general/interesting-articles/index.html
+++ b/researching-is-living/general/interesting-articles/index.html
@@ -1,4 +1,4 @@
- 有趣文章 - c01dkit's tech blog      

有趣文章

约 179 个字 预计阅读时间 1 分钟

  1. [Usenix Security 2021] Understanding and Detecting Disordered Error Handling with Precise Function Pairing 不正确的错误处理函数本身可能也会带来新的错误,尤其是在做一些前期清理工作时,执行顺序不正确会带来提权、崩溃与DoS。本文希望推断出预期的清理函数。
  2. [Usenix Security 2020] Actions Speak Louder than Words: Entity-Sensitive Privacy Policy and Data Flow Analysis with PoliCheck 考虑到数据流向的实体,对应用程序的隐私规范进行研究建模。
  3. [NDSS 2019] https://www.youtube.com/watch?v=dMndb0Xmr4k&t=1s&list=PLfUWWM-POgQs9SPvg-UA-TNG7UVEcdz8l&index=5 GitHub上由于一些不当操作可能会导致API密钥泄露。本文研究表明这种泄露非常猖獗,并且远没有解决问题。

有趣文章

约 179 个字 预计阅读时间 1 分钟

  1. [Usenix Security 2021] Understanding and Detecting Disordered Error Handling with Precise Function Pairing 不正确的错误处理函数本身可能也会带来新的错误,尤其是在做一些前期清理工作时,执行顺序不正确会带来提权、崩溃与DoS。本文希望推断出预期的清理函数。
  2. [Usenix Security 2020] Actions Speak Louder than Words: Entity-Sensitive Privacy Policy and Data Flow Analysis with PoliCheck 考虑到数据流向的实体,对应用程序的隐私规范进行研究建模。
  3. [NDSS 2019] https://www.youtube.com/watch?v=dMndb0Xmr4k&t=1s&list=PLfUWWM-POgQs9SPvg-UA-TNG7UVEcdz8l&index=5 GitHub上由于一些不当操作可能会导致API密钥泄露。本文研究表明这种泄露非常猖獗,并且远没有解决问题。

四大调查

约 311 个字 预计阅读时间 1 分钟

  1. [Usenix Security 2022] “I feel invaded, annoyed, anxious and I may protect myself”: Individuals’ Feelings about Online Tracking and their Protective Behaviour across Gender and Country
  2. [Usenix Security 2022] “Like Lesbians Walking the Perimeter”: Experiences of U.S. LGBTQ+ Folks With Online Security, Safety, and Privacy Advice
  3. [Usenix Security 2022] How and Why People Use Virtual Private Networks
  4. [Usenix Security 2021] “It’s the Company, the Government, You and I”: User Perceptions of Responsibility for Smart Home Privacy and Security
  5. [Usenix Security 2021] “Shhh…be quiet!” Reducing the Unwanted Interruptions of Notification Permission Prompts on Chrome
  6. [Usenix Security 2021] Effect of Mood, Location, Trust, and Presence of Others on Video-Based Social Authentication
  7. [Usenix Security 2021] ‘Passwords Keep Me Safe’ – Understanding What Children Think about Passwords
  8. [Usenix Security 2021] “It’s stressful having all these phones”: Investigating Sex Workers’ Safety Goals, Risks, and Practices Online
  9. [Usenix Security 2021] “Now I’m a bit angry:” Individuals’ Awareness, Perception, and Responses to Data Breaches that Affected Them
  10. [Usenix Security 2020] “I am uncomfortable sharing what I can’t see”: Privacy Concerns of the Visually Impaired with Camera Based Assistive Applications
  11. [Usenix Security 2020 | Distingguished Paper Award] Understanding security mistakes developers make: Qualitative analysis from Build It, Break It, Fix It
  12. [Usenix Security 2020] An Observational Investigation of Reverse Engineers’ Processes
  13. [Usenix Security 2020] That Was Then, This Is Now: A Security Evaluation of Password Generation, Storage, and Autofill in Browser-Based Password Managers
  14. [NDSS 2022] An In-depth Analysis of Duplicated Linux Kernel Bug Reports
  15. [NDSS 2020] Are You Going to Answer That? Measuring User Responses to Anti-Robocall Application Indicators
  16. [NDSS 2019] Time Does Not Heal All Wounds: A Longitudinal Analysis of Security-Mechanism Support in Mobile Browsers
  17. [NDSS 2019] A First Look into the Facebook Advertising Ecosystem

四大调查

约 311 个字 预计阅读时间 1 分钟

  1. [Usenix Security 2022] “I feel invaded, annoyed, anxious and I may protect myself”: Individuals’ Feelings about Online Tracking and their Protective Behaviour across Gender and Country
  2. [Usenix Security 2022] “Like Lesbians Walking the Perimeter”: Experiences of U.S. LGBTQ+ Folks With Online Security, Safety, and Privacy Advice
  3. [Usenix Security 2022] How and Why People Use Virtual Private Networks
  4. [Usenix Security 2021] “It’s the Company, the Government, You and I”: User Perceptions of Responsibility for Smart Home Privacy and Security
  5. [Usenix Security 2021] “Shhh…be quiet!” Reducing the Unwanted Interruptions of Notification Permission Prompts on Chrome
  6. [Usenix Security 2021] Effect of Mood, Location, Trust, and Presence of Others on Video-Based Social Authentication
  7. [Usenix Security 2021] ‘Passwords Keep Me Safe’ – Understanding What Children Think about Passwords
  8. [Usenix Security 2021] “It’s stressful having all these phones”: Investigating Sex Workers’ Safety Goals, Risks, and Practices Online
  9. [Usenix Security 2021] “Now I’m a bit angry:” Individuals’ Awareness, Perception, and Responses to Data Breaches that Affected Them
  10. [Usenix Security 2020] “I am uncomfortable sharing what I can’t see”: Privacy Concerns of the Visually Impaired with Camera Based Assistive Applications
  11. [Usenix Security 2020 | Distingguished Paper Award] Understanding security mistakes developers make: Qualitative analysis from Build It, Break It, Fix It
  12. [Usenix Security 2020] An Observational Investigation of Reverse Engineers’ Processes
  13. [Usenix Security 2020] That Was Then, This Is Now: A Security Evaluation of Password Generation, Storage, and Autofill in Browser-Based Password Managers
  14. [NDSS 2022] An In-depth Analysis of Duplicated Linux Kernel Bug Reports
  15. [NDSS 2020] Are You Going to Answer That? Measuring User Responses to Anti-Robocall Application Indicators
  16. [NDSS 2019] Time Does Not Heal All Wounds: A Longitudinal Analysis of Security-Mechanism Support in Mobile Browsers
  17. [NDSS 2019] A First Look into the Facebook Advertising Ecosystem

latex基础

约 21 个字 190 行代码 预计阅读时间 19 分钟

推荐工具

使用Table Generator绘制表格

英文latex

\documentclass[conference,11pt]{IEEEtran}
+      

latex基础

约 21 个字 190 行代码 预计阅读时间 19 分钟

推荐工具

使用Table Generator绘制表格

英文latex

\documentclass[conference,11pt]{IEEEtran}
 \IEEEoverridecommandlockouts
 % The preceding line is only needed to identify funding in the first footnote. If that is unneeded, please comment it out.
 \usepackage{cite}
diff --git a/researching-is-living/general/picking-ups/index.html b/researching-is-living/general/picking-ups/index.html
index 9f84746..af3c467 100644
--- a/researching-is-living/general/picking-ups/index.html
+++ b/researching-is-living/general/picking-ups/index.html
@@ -1,4 +1,4 @@
- 文句摘录 - c01dkit's tech blog      

文句摘录

约 1043 个字 预计阅读时间 3 分钟

Alligator in Vest: A Practical Failure-Diagnosis Framework via Arm Hardware Features (ISSTA 2023)

  • In light of these limitations, we propose Investigator, a practical failure diagnosis framework on Arm to fulfill the three requirements.

RR: A Fault Model for Efficient TEE Replication (NDSS 2023)

  • The correctness of replication protocols hinges on the property of quorum intersection.
  • In quorum-based protocols, this property is enforced by ensuring that any pair of quorums intersects in at least one replica that does not deviate from its prescribed behavior.

No Grammar, No Problem: Towards Fuzzing the Linux Kernel without System-Call Descriptions (NDSS 2023)

  • However, the process of manually collecting system-call traces, or writing descriptions is prone to human-error: the immediate coverage gains from descriptions and traces risk obscuring parts of the code that the fuzzer can no longer exercise meaningfully.

FUZZUSB: Hybrid Stateful Fuzzing of USB Gadget Stacks (Oakland 2022)

  • While the prevalence and versatility of USB have made our daily life convenient, it has also attracted attackers seeking to exploit vulnerabilities within the USB ecosystem.

Registered Report: DATAFLOW Towards a Data-Flow-Guided Fuzzer

  • Unfortunately, these more accurate analyses incur a high run-time penalty, impeding fuzzer throughput.
  • Unlike DTA, which strives for accuracy, we take inspiration from popular greybox fuzzers (e.g., AFL) and embrace some imprecision in an effort to reduce overhead and thus maximize fuzzing throughput.

A Survey on Adversarial Attacks for Malware Analysis

  • Adversarial attacks has now emerged as a serious concern, threatening to dismantle and undermine all the progress made in the machine learning domain.
  • The fear of evolving adversarial attack is growing among the cyber security research community and has provoked the everlasting war between adversarial attackers and defenders.

Survivalism: Systematic Analysis of Windows Malware Living-Off-The-Land (Oakland 2021)

  • Orthogonal to our research is the analysis and deobfuscation of script-based malware.

A Systematical and longitudinal study of evasive behaviors in windows malware (Computers & Security 2021)

  • Using our framework and taxonomy, we study the evasive behaviors adopted by 45,375 malware samples observed in the wild between 2010 and 201*
  • We harvest papers, reports, and blog posts from the security community estimating the influence of the public disclosure of evasive techniques on their adoption in the wild.

Structural Attack against Graph Based Android Malware Detection (CCS 2021)

  • Graph-based detection methods extract features from graphs and use these features to train classifiers for malware detection. By contrast, structural attacks directly modify the graph features and thus they are more intrinsic and effective.

Deep Learning for Android Malware Defenses: a Systematic Literature Review (ACM Survey 2021)

  • In front of the increasing difficulties of Android malware detection, it is non-trivial to build a robust and transparent detecting model or system only by traditional machine learning techniques.

Intriguing Properties of Adversarial ML Attacks in the Problem Space (Oakland 2020)

  • We shed light on the relationship between feature space and problem space, and we introduce the concept of side-effect features as the byproduct of the inverse feature-mapping problem. This enables us to define and prove necessary and sufficient conditions for the existence of problem-space attacks.

P2IM: Scalable and Hardware-independent Firmware Testing via Automatic Peripheral Interface Modeling (USENIX SECURITY 2020)

  • The inapplicability of fuzzers on MCU boils down to the lack of a platform where firmware can execute while taking inputs from fuzzers.
  • Although the register access patterns and the type identification method are purely empirical, we find that in practice they work fairly reliably and accurately across a wide range of peripheral devices. We attribute this practical and promising results to two factors.
  • The instantiation is on-demand and interleaved with the firmware fuzzing/testing process.

Toward the Analysis of Embedded Firmware through Automated Re-hosting (RAID 2019)

  • Unfortunately for security researchers, in stark contrast to the desktop and mobile ecosystems, market forces have not created any de facto standard for components, protocols, or software, hampering existing program analysis approaches, and making the understanding of each new device an independent, mostly manual, time-consuming effort.
  • In this work, we develop an approach to re-hosting that achieves all of them, and propose a proof-of-concept system, called PRETENDER, which is able to observe hardware-firmware interactions and create models of hardware peripherals automatically.
  • To deal with the plethora of software applications that need to be analyzed on desktop and mobile platforms, the security community has developed many techniques for enabling the scalable analysis of programs to find bugs and detect malice.
  • Dynamic approaches typically rely on virtualization to enable parallel, scalable analyses, while symbolic approaches rely on function summarization of the underlying operating system to minimize the code that they need to execute. In order to use any of these tools, the analyst must take the program out of its original execution environment, and provide a suitable analysis environment able to execute it. This is a process referred to as re-hosting.

REPT: Reverse Debugging of Failures in Deployed Software (USENIX SECURITY 2018)

  • Moreover, even though root cause diagnosis can help a developer determine the reasons behind a failure, developers often require a deeper understanding of the conditions and the state leading to a failure to fix a bug, which these systems do not provide.

What You Corrupt Is Not What You Crash: Challenges in Fuzzing Embedded Devices (NDSS 2018)

  • As a result, silent memory corruptions occur more frequently on embedded devices than on traditional computer systems, creating a significant challenge for conducting fuzzing sessions on embedded systems software.

Postmortem Program Analysis with Hardware-Enhanced Post-Crash Artifacts (USENIX SECURITY 2017)

  • As such, it is tedious and arduous for a software developer to plow through an execution trace to diagnose the root cause of a software failure.
  • Given that backward taint analysis mimics how a software developer (or security analyst) typically diagnoses the root cause of a program failure, this observation indicates that POMP has a great potential to reduce manual efforts in failure diagnosis.

POMP++: Facilitating Postmortem Program Diagnosis with Value-Set Analysis

  • Briefly speaking, postmortem program diagnosis is to identify the program statements pertaining to the crash, analyze these statements, and eventually figure out why a bad value was passed to the crash site.

A Survey on Software Fault Localization (TSE 2016)

  • Furthermore, manual fault localization relies heavily on the software developer’s experience, judgment, and intuition to identify and prioritize code that is likely to be faulty.

文句摘录

约 1043 个字 预计阅读时间 3 分钟

Alligator in Vest: A Practical Failure-Diagnosis Framework via Arm Hardware Features (ISSTA 2023)

  • In light of these limitations, we propose Investigator, a practical failure diagnosis framework on Arm to fulfill the three requirements.

RR: A Fault Model for Efficient TEE Replication (NDSS 2023)

  • The correctness of replication protocols hinges on the property of quorum intersection.
  • In quorum-based protocols, this property is enforced by ensuring that any pair of quorums intersects in at least one replica that does not deviate from its prescribed behavior.

No Grammar, No Problem: Towards Fuzzing the Linux Kernel without System-Call Descriptions (NDSS 2023)

  • However, the process of manually collecting system-call traces, or writing descriptions is prone to human-error: the immediate coverage gains from descriptions and traces risk obscuring parts of the code that the fuzzer can no longer exercise meaningfully.

FUZZUSB: Hybrid Stateful Fuzzing of USB Gadget Stacks (Oakland 2022)

  • While the prevalence and versatility of USB have made our daily life convenient, it has also attracted attackers seeking to exploit vulnerabilities within the USB ecosystem.

Registered Report: DATAFLOW Towards a Data-Flow-Guided Fuzzer

  • Unfortunately, these more accurate analyses incur a high run-time penalty, impeding fuzzer throughput.
  • Unlike DTA, which strives for accuracy, we take inspiration from popular greybox fuzzers (e.g., AFL) and embrace some imprecision in an effort to reduce overhead and thus maximize fuzzing throughput.

A Survey on Adversarial Attacks for Malware Analysis

  • Adversarial attacks has now emerged as a serious concern, threatening to dismantle and undermine all the progress made in the machine learning domain.
  • The fear of evolving adversarial attack is growing among the cyber security research community and has provoked the everlasting war between adversarial attackers and defenders.

Survivalism: Systematic Analysis of Windows Malware Living-Off-The-Land (Oakland 2021)

  • Orthogonal to our research is the analysis and deobfuscation of script-based malware.

A Systematical and longitudinal study of evasive behaviors in windows malware (Computers & Security 2021)

  • Using our framework and taxonomy, we study the evasive behaviors adopted by 45,375 malware samples observed in the wild between 2010 and 201*
  • We harvest papers, reports, and blog posts from the security community estimating the influence of the public disclosure of evasive techniques on their adoption in the wild.

Structural Attack against Graph Based Android Malware Detection (CCS 2021)

  • Graph-based detection methods extract features from graphs and use these features to train classifiers for malware detection. By contrast, structural attacks directly modify the graph features and thus they are more intrinsic and effective.

Deep Learning for Android Malware Defenses: a Systematic Literature Review (ACM Survey 2021)

  • In front of the increasing difficulties of Android malware detection, it is non-trivial to build a robust and transparent detecting model or system only by traditional machine learning techniques.

Intriguing Properties of Adversarial ML Attacks in the Problem Space (Oakland 2020)

  • We shed light on the relationship between feature space and problem space, and we introduce the concept of side-effect features as the byproduct of the inverse feature-mapping problem. This enables us to define and prove necessary and sufficient conditions for the existence of problem-space attacks.

P2IM: Scalable and Hardware-independent Firmware Testing via Automatic Peripheral Interface Modeling (USENIX SECURITY 2020)

  • The inapplicability of fuzzers on MCU boils down to the lack of a platform where firmware can execute while taking inputs from fuzzers.
  • Although the register access patterns and the type identification method are purely empirical, we find that in practice they work fairly reliably and accurately across a wide range of peripheral devices. We attribute this practical and promising results to two factors.
  • The instantiation is on-demand and interleaved with the firmware fuzzing/testing process.

Toward the Analysis of Embedded Firmware through Automated Re-hosting (RAID 2019)

  • Unfortunately for security researchers, in stark contrast to the desktop and mobile ecosystems, market forces have not created any de facto standard for components, protocols, or software, hampering existing program analysis approaches, and making the understanding of each new device an independent, mostly manual, time-consuming effort.
  • In this work, we develop an approach to re-hosting that achieves all of them, and propose a proof-of-concept system, called PRETENDER, which is able to observe hardware-firmware interactions and create models of hardware peripherals automatically.
  • To deal with the plethora of software applications that need to be analyzed on desktop and mobile platforms, the security community has developed many techniques for enabling the scalable analysis of programs to find bugs and detect malice.
  • Dynamic approaches typically rely on virtualization to enable parallel, scalable analyses, while symbolic approaches rely on function summarization of the underlying operating system to minimize the code that they need to execute. In order to use any of these tools, the analyst must take the program out of its original execution environment, and provide a suitable analysis environment able to execute it. This is a process referred to as re-hosting.

REPT: Reverse Debugging of Failures in Deployed Software (USENIX SECURITY 2018)

  • Moreover, even though root cause diagnosis can help a developer determine the reasons behind a failure, developers often require a deeper understanding of the conditions and the state leading to a failure to fix a bug, which these systems do not provide.

What You Corrupt Is Not What You Crash: Challenges in Fuzzing Embedded Devices (NDSS 2018)

  • As a result, silent memory corruptions occur more frequently on embedded devices than on traditional computer systems, creating a significant challenge for conducting fuzzing sessions on embedded systems software.

Postmortem Program Analysis with Hardware-Enhanced Post-Crash Artifacts (USENIX SECURITY 2017)

  • As such, it is tedious and arduous for a software developer to plow through an execution trace to diagnose the root cause of a software failure.
  • Given that backward taint analysis mimics how a software developer (or security analyst) typically diagnoses the root cause of a program failure, this observation indicates that POMP has a great potential to reduce manual efforts in failure diagnosis.

POMP++: Facilitating Postmortem Program Diagnosis with Value-Set Analysis

  • Briefly speaking, postmortem program diagnosis is to identify the program statements pertaining to the crash, analyze these statements, and eventually figure out why a bad value was passed to the crash site.

A Survey on Software Fault Localization (TSE 2016)

  • Furthermore, manual fault localization relies heavily on the software developer’s experience, judgment, and intuition to identify and prioritize code that is likely to be faulty.

文章阅读

约 156 个字 预计阅读时间 1 分钟

综合性知识学习

会议总结

软件供应链

大模型

Google

编程语言

磨刀不误砍柴工

文章阅读

约 337 个字 预计阅读时间 1 分钟

综合性知识学习

会议总结

报告PPT

AI 安全

软件供应链

网络流量识别

大模型

Google

编程语言

磨刀不误砍柴工

科研心得

约 508 个字 预计阅读时间 2 分钟

养成习惯

时间过得总是非常快的。忙着做一个课题,可能每天感觉不到有什么进展呢,半年一年就过去了。如果有这种想法,多半是没做好规划,像个无头苍蝇一样东闯西撞。

感觉有两个习惯是必须养成的,一是读论文要思考问题与意义:看到题目和摘要,思考这篇文章希望解决什么问题、这个问题有什么价值、解决这个问题有什么思路、会遇到哪些普遍与特殊的挑战,以及文章基于哪些假设并且会试图避而不谈的缺陷;二是每天进行总结与归纳,思考一天到底有什么进展,凝练总结成文字或ppt讲稿。每天光看不总结,等于白看!平时对各种问题就要有所准备与思考,不要别人问起的时候就敷衍地给一个回答,没有意义。

早上写todo list,晚上写done list,看看这一天进展如何。是否有没做完的事情,是否有分心做了别的事情,明天如何规划时间……对自己每天、每周、每月能做的事情有清楚的认识,不盲目自大也不妄自菲薄。

做任何事都要给一个清晰的ddl,督促尽快完成不要拖沓。另一方面是为了限制思考,要集中、快速,不要漫无目的地发散。比如读论文前思考这篇文章需要解决的挑战时,限定在3min之内,超时以后无论是否想到多少都要停下来。也可以有效避免分心。

科研写作

科研写作需要系统的训练。每天愉快地读、写一小时,长期坚持,叫做“read and write”。

写文章要弄清楚读者都是同专业的人,因此要体现出专业性与科学性、精确性、简洁性、逻辑性。

科研心得

约 508 个字 预计阅读时间 2 分钟

养成习惯

时间过得总是非常快的。忙着做一个课题,可能每天感觉不到有什么进展呢,半年一年就过去了。如果有这种想法,多半是没做好规划,像个无头苍蝇一样东闯西撞。

感觉有两个习惯是必须养成的,一是读论文要思考问题与意义:看到题目和摘要,思考这篇文章希望解决什么问题、这个问题有什么价值、解决这个问题有什么思路、会遇到哪些普遍与特殊的挑战,以及文章基于哪些假设并且会试图避而不谈的缺陷;二是每天进行总结与归纳,思考一天到底有什么进展,凝练总结成文字或ppt讲稿。每天光看不总结,等于白看!平时对各种问题就要有所准备与思考,不要别人问起的时候就敷衍地给一个回答,没有意义。

早上写todo list,晚上写done list,看看这一天进展如何。是否有没做完的事情,是否有分心做了别的事情,明天如何规划时间……对自己每天、每周、每月能做的事情有清楚的认识,不盲目自大也不妄自菲薄。

做任何事都要给一个清晰的ddl,督促尽快完成不要拖沓。另一方面是为了限制思考,要集中、快速,不要漫无目的地发散。比如读论文前思考这篇文章需要解决的挑战时,限定在3min之内,超时以后无论是否想到多少都要停下来。也可以有效避免分心。

科研写作

科研写作需要系统的训练。每天愉快地读、写一小时,长期坚持,叫做“read and write”。

写文章要弄清楚读者都是同专业的人,因此要体现出专业性与科学性、精确性、简洁性、逻辑性。

情景模板

约 468 个字 预计阅读时间 2 分钟

提出本文工作:

  • In this paper, we propose a novel approach to fault localization, SmartFL, that considers the four factors via efficient probabilistic modeling of the program semantics.
  • In this work, we propose POMP++, a system to address the above limitations in analyzing a post-crash artifact and pinpointing statements pertaining to the crash.
  • In this paper, we present REPT, a practical system that enables reverse debugging of software failures in deployed systems.

介绍某一流程在整体系统中的作用:

  • During program debugging, fault localization is the activity of identifying the exact locations of program faults.

说明某一步骤并非简单的:

  • However, identifying the bug-inducing commit precisely for a bug-revealing test can be non-trivial due to the following reasons.

凝练本文实验效果:

  • We design and implement REPT, deploy it on Microsoft Windows, and integrate it into WinDbg. We evaluate REPT on 16 real-world bugs and show that it can recover data values accurately (92% on average) and efficiently (in less than 20 seconds) for these bugs. We also show that it enables effective reverse debugging for 14 bugs.

提出本文novelty:

  • The novelty of this work lies in two aspects. First, we propose a new VSA-based approach for memory alias verification. xxx. Second, we develop new schemes to incorporate our customized VSA to POMP. xxx.

提出本文insight:

  • Our core insight is that the probability of a fault in the current program element leads to the current test results can be efficiently estimated by analyzing the following:

准备开始介绍技术细节:

  • In this section, we elaborate on the technical details of our xxx approach. First, we describe how to xxx. Second, we discuss how to xxx. Finally, we discuss how to xxx.
  • As we elaborate below, the reasons behind this are two folds.

说目前的工作研究的主要内容受限、别的方法存在问题:

  • However, it inevitably detours the fuzzing program away from the critical objects.
  • Existing approaches either consider the full semantics of the program (e.g., mutation-based fault localization and angelic debugging), leading to scalability issues, or ignore the semantics of the program (e.g., spectrum-based fault localization), leading to imprecise localization results.
  • However, all existing approaches only consider whether a program entity exists in samples but neglect the execution times of the entities in a certain sample and the sequence of their executions. As demonstrated in Section 5, without such sequence information, program spectrum-based fault localization would inevitably introduce imprecision.

一些工作细节:

  • In our work, we manually annotate all these sinks based on their naming patterns.

情景模板

约 468 个字 预计阅读时间 2 分钟

提出本文工作:

  • In this paper, we propose a novel approach to fault localization, SmartFL, that considers the four factors via efficient probabilistic modeling of the program semantics.
  • In this work, we propose POMP++, a system to address the above limitations in analyzing a post-crash artifact and pinpointing statements pertaining to the crash.
  • In this paper, we present REPT, a practical system that enables reverse debugging of software failures in deployed systems.

介绍某一流程在整体系统中的作用:

  • During program debugging, fault localization is the activity of identifying the exact locations of program faults.

说明某一步骤并非简单的:

  • However, identifying the bug-inducing commit precisely for a bug-revealing test can be non-trivial due to the following reasons.

凝练本文实验效果:

  • We design and implement REPT, deploy it on Microsoft Windows, and integrate it into WinDbg. We evaluate REPT on 16 real-world bugs and show that it can recover data values accurately (92% on average) and efficiently (in less than 20 seconds) for these bugs. We also show that it enables effective reverse debugging for 14 bugs.

提出本文novelty:

  • The novelty of this work lies in two aspects. First, we propose a new VSA-based approach for memory alias verification. xxx. Second, we develop new schemes to incorporate our customized VSA to POMP. xxx.

提出本文insight:

  • Our core insight is that the probability of a fault in the current program element leads to the current test results can be efficiently estimated by analyzing the following:

准备开始介绍技术细节:

  • In this section, we elaborate on the technical details of our xxx approach. First, we describe how to xxx. Second, we discuss how to xxx. Finally, we discuss how to xxx.
  • As we elaborate below, the reasons behind this are two folds.

说目前的工作研究的主要内容受限、别的方法存在问题:

  • However, it inevitably detours the fuzzing program away from the critical objects.
  • Existing approaches either consider the full semantics of the program (e.g., mutation-based fault localization and angelic debugging), leading to scalability issues, or ignore the semantics of the program (e.g., spectrum-based fault localization), leading to imprecise localization results.
  • However, all existing approaches only consider whether a program entity exists in samples but neglect the execution times of the entities in a certain sample and the sequence of their executions. As demonstrated in Section 5, without such sequence information, program spectrum-based fault localization would inevitably introduce imprecision.

一些工作细节:

  • In our work, we manually annotate all these sinks based on their naming patterns.

词汇学习

约 943 个字 预计阅读时间 3 分钟

  • encyclopedic 广博的
  • unprecedented 史无前例的,空前的
  • bluntly 直言不讳地
  • as per some estimates 根据一些估计
  • indispensable 必不可少的
  • to name just a few 仅举几例
  • discriminate 鉴别,区别;有区别的
  • remediation 整治
  • cumbersome 繁琐的
  • drastically 剧烈地
  • impede 阻碍
  • stochastic 随机的
  • sharp-edged plateau
  • saturating 饱和的
  • avert 避免,纾解
  • delineation 划定
  • nuisance 滋扰
  • menace 威胁,危险的人或物
  • dismantle 拆开,拆卸,废除
  • undermine 暗中破坏,从根基处损坏
  • provoke 激起,引起
  • ransomware 勒索软件
  • withstand 抵挡,经受住,抵抗
  • camouflage 伪装,隐蔽,欺瞒
  • influx 大量涌入,汇集
  • nullify 使无效,作废,取消
  • calibrate 校准
  • ameliorate 改善,改良
  • prolifical 多产的
  • henceforth 从今以后,今后
  • surmise 推测
  • smuggle 走私
  • prudent 谨慎的
  • intriguing 有趣的,迷人的
  • byproduct 副产品,意外结果
  • inconspicuous 不明显的 不引人注目的
  • brittle 易碎的,难以相处的,尖刻暴躁的,冷淡的
  • deceive 欺骗,误导
  • versatility 多才多艺,多用途,易变,可转动性
  • inflate 使膨胀,使充气,物价上涨
  • conflate 合并,混合
  • incentive 动机,刺激,诱因,鼓励
  • bounty 赏金,奖金,赠物
  • exacerbate 使恶化,使加重
  • fluctuation 波动,涨落,起伏
  • susceptible 易受影响的,易受感染的,可以接受或允许的
  • extraneous 外来的,外部的,无关的
  • amenable (对法律等)负责的,易控制的;经得起检验或考查的
  • vicinity 附近,临近,附近地区,大约的程度或数量
  • retention 保留,记忆力,保持力,滞留,扣留
  • suffice 足够,有能力,满足……的需要,使满足
  • rudimentary 简陋的
  • inadvertently 漫不经心地,疏忽地
  • cease 停止,终止
  • collectively 全体地,共同地
  • daunting 令人畏惧的,使人气馁的
  • encompass 围绕,包围,包含,包括
  • devastating 毁灭性的,令人震惊的
  • retrofit 给机器设备装配(新部件),翻新,改型
  • yield to 让步于,使自己受到xxx的支配
  • sterilizer 消毒者,消毒器
  • salient 显著的,突出的,跳跃的,(角)凸出的
  • nuanced 有细微差别的
  • discern 察觉出,了解;分辨出
  • subsidised 补贴的
  • culprit 犯人,罪犯
  • holistic 全盘的,整体的,功能整体性的
  • endeavor 努力,尽力
  • influx 注入,流入,汇集
  • plausible 貌似真实的,貌似有理的,花言巧语的
  • pertain 有关,存在,适用
  • obsolescence 废弃,陈旧过时,(器官)废退
  • resort to 诉诸,依靠,求助于
  • discrepancy 差异,不一致,区别
  • impair 损害,削弱
  • hefty 重的,健壮的,异常大的,重量级的
  • paucity 少量,缺乏,不足,缺少
  • obstruct 阻碍,阻止,妨碍
  • retention 保留,记忆力,滞留,扣留
  • envision 设想,预想 vt.
  • remediate 补救,治疗,矫正,修复
  • conundrum 谜语,难解的问题
  • depict 展示,描述,显示
  • expedite 加快进展
  • remedy 治疗法,改正,改进,补救
  • instinctive reaction 本能反应
  • deem 认为,视为,相信
  • detour 绕路,绕道,弯路
  • futile 无效的,没用的
  • the hassle of sth. 某事带来的麻烦
  • unencumbered 没有阻碍的,不受妨碍的,无负担的
  • idiosyncrasy (某人特有的)气质,习性,癖好
  • crowdsource 众包
  • stabilize 固定,防止……波动
  • encompass 围绕,包围,完成
  • obviate 避免,消除(贫困、不方便等)
  • conducive to有助于……的,有益于……的
  • pertain to 有关,关于
  • arduous 努力的,艰巨的,难克服的
  • plow 犁,耕, 费力穿过
  • imperative 必要的,不可避免的;必要的事,命令,规则
  • notoriously 臭名昭著地,众所周知地
  • culprit 犯人,罪犯,被告人,肇事者
  • succinct 简洁的
  • reciprocal 互惠的,倒数
  • inadvertent 不经意的,疏忽的
  • disseminate 散布,传播(问卷等)
  • elicitation 引出,启发
  • obsolete 废弃的,老式的,已过时的
  • In particular, it works like SBFL, where a bug-inducing commit and a non-inducing commit are analogous(相似的,可比拟的) to a failing test and a passing test in SBFL, respectively.
  • The effectiveness of recurrent neural network is marginally(略微地) higher than multi-layer perceptron.

词汇学习

约 943 个字 预计阅读时间 3 分钟

  • encyclopedic 广博的
  • unprecedented 史无前例的,空前的
  • bluntly 直言不讳地
  • as per some estimates 根据一些估计
  • indispensable 必不可少的
  • to name just a few 仅举几例
  • discriminate 鉴别,区别;有区别的
  • remediation 整治
  • cumbersome 繁琐的
  • drastically 剧烈地
  • impede 阻碍
  • stochastic 随机的
  • sharp-edged plateau
  • saturating 饱和的
  • avert 避免,纾解
  • delineation 划定
  • nuisance 滋扰
  • menace 威胁,危险的人或物
  • dismantle 拆开,拆卸,废除
  • undermine 暗中破坏,从根基处损坏
  • provoke 激起,引起
  • ransomware 勒索软件
  • withstand 抵挡,经受住,抵抗
  • camouflage 伪装,隐蔽,欺瞒
  • influx 大量涌入,汇集
  • nullify 使无效,作废,取消
  • calibrate 校准
  • ameliorate 改善,改良
  • prolifical 多产的
  • henceforth 从今以后,今后
  • surmise 推测
  • smuggle 走私
  • prudent 谨慎的
  • intriguing 有趣的,迷人的
  • byproduct 副产品,意外结果
  • inconspicuous 不明显的 不引人注目的
  • brittle 易碎的,难以相处的,尖刻暴躁的,冷淡的
  • deceive 欺骗,误导
  • versatility 多才多艺,多用途,易变,可转动性
  • inflate 使膨胀,使充气,物价上涨
  • conflate 合并,混合
  • incentive 动机,刺激,诱因,鼓励
  • bounty 赏金,奖金,赠物
  • exacerbate 使恶化,使加重
  • fluctuation 波动,涨落,起伏
  • susceptible 易受影响的,易受感染的,可以接受或允许的
  • extraneous 外来的,外部的,无关的
  • amenable (对法律等)负责的,易控制的;经得起检验或考查的
  • vicinity 附近,临近,附近地区,大约的程度或数量
  • retention 保留,记忆力,保持力,滞留,扣留
  • suffice 足够,有能力,满足……的需要,使满足
  • rudimentary 简陋的
  • inadvertently 漫不经心地,疏忽地
  • cease 停止,终止
  • collectively 全体地,共同地
  • daunting 令人畏惧的,使人气馁的
  • encompass 围绕,包围,包含,包括
  • devastating 毁灭性的,令人震惊的
  • retrofit 给机器设备装配(新部件),翻新,改型
  • yield to 让步于,使自己受到xxx的支配
  • sterilizer 消毒者,消毒器
  • salient 显著的,突出的,跳跃的,(角)凸出的
  • nuanced 有细微差别的
  • discern 察觉出,了解;分辨出
  • subsidised 补贴的
  • culprit 犯人,罪犯
  • holistic 全盘的,整体的,功能整体性的
  • endeavor 努力,尽力
  • influx 注入,流入,汇集
  • plausible 貌似真实的,貌似有理的,花言巧语的
  • pertain 有关,存在,适用
  • obsolescence 废弃,陈旧过时,(器官)废退
  • resort to 诉诸,依靠,求助于
  • discrepancy 差异,不一致,区别
  • impair 损害,削弱
  • hefty 重的,健壮的,异常大的,重量级的
  • paucity 少量,缺乏,不足,缺少
  • obstruct 阻碍,阻止,妨碍
  • retention 保留,记忆力,滞留,扣留
  • envision 设想,预想 vt.
  • remediate 补救,治疗,矫正,修复
  • conundrum 谜语,难解的问题
  • depict 展示,描述,显示
  • expedite 加快进展
  • remedy 治疗法,改正,改进,补救
  • instinctive reaction 本能反应
  • deem 认为,视为,相信
  • detour 绕路,绕道,弯路
  • futile 无效的,没用的
  • the hassle of sth. 某事带来的麻烦
  • unencumbered 没有阻碍的,不受妨碍的,无负担的
  • idiosyncrasy (某人特有的)气质,习性,癖好
  • crowdsource 众包
  • stabilize 固定,防止……波动
  • encompass 围绕,包围,完成
  • obviate 避免,消除(贫困、不方便等)
  • conducive to有助于……的,有益于……的
  • pertain to 有关,关于
  • arduous 努力的,艰巨的,难克服的
  • plow 犁,耕, 费力穿过
  • imperative 必要的,不可避免的;必要的事,命令,规则
  • notoriously 臭名昭著地,众所周知地
  • culprit 犯人,罪犯,被告人,肇事者
  • succinct 简洁的
  • reciprocal 互惠的,倒数
  • inadvertent 不经意的,疏忽的
  • disseminate 散布,传播(问卷等)
  • elicitation 引出,启发
  • obsolete 废弃的,老式的,已过时的
  • In particular, it works like SBFL, where a bug-inducing commit and a non-inducing commit are analogous(相似的,可比拟的) to a failing test and a passing test in SBFL, respectively.
  • The effectiveness of recurrent neural network is marginally(略微地) higher than multi-layer perceptron.

Index

约 0 个字 预计阅读时间不到 1 分钟

Index

约 0 个字 预计阅读时间不到 1 分钟

模糊测试基本介绍

约 1699 个字 2 行代码 预计阅读时间 6 分钟

覆盖率指引的模糊测试方法获得覆盖率的四种追踪方式1

  1. 使用编译器向基本块边缘插桩,可以准确地插桩并易于优化,但需要源码已知。
  2. 静态二进制重写,不需要源码,仍在研究,因为静态代码插桩准确性难以保证,并且优化能力有限。这些限制条件会影响代码率信息的质量与准确性,以及二进制重写的表现。
  3. 动态二进制插桩,不需要源码,可以容易、准确插入代码,但是动态翻译二进制的开销可能大到不能接受。
  4. 硬件辅助追踪,不需要源码,利用内置的硬件追踪扩展,在运行时直接获取控制执行流信息。

侵入式与非侵入式追踪2

Traces can be generated by trace code that is executed within tasks and/or interrupt service routines, just like application code that is executed on the same CPU. This is the most flexible approach, as both the content and the amount of trace information output can be defined in software. However, this tracing method comes with a significant drawback: It uses resources that are shared with the application software, hence tracing may significantly reduce the amount of memory available for the applications, increase the gross execution times of the applications and, in the case of real-time systems, impair functionality. This is why it is called intrusive tracing.

The most common case is that adding trace code is detrimental to the functionality of the applications in real-time systems because the resource requirements for intrusive tracing have been underestimated in the early stages of the project, such that tracing would eventually eat up resources that are required by the application. Therefore, the resource requirements for tracing must be properly considered throughout the whole development lifecycle. Removing trace code from real-time systems may also cause functional issues, typically just before the final production software release. This is the worst case, as trace information is no longer available in this scenario.

Non-intrusive tracing does not change the intrinsic timing behavior of the system under test. This approach simplifies the software development process a lot and requires dedicated hardware support for tracing. External trace probes connected to the target system, in conjunction with on-chip debug modules, capture code execution on instruction level, memory accesses and other events on the target processor. This approach is the best option when it comes to debugging the code execution down to the instruction level. The PCB design of the device under test must provide the connectors required by the external probe.

Another option for non-intrusive tracing is on-chip tracing, where most of the trace hardware is packed into the same chip that also contains the CPU that executes the application code. Non-intrusive tracing can, however, be restricted by limitations of the respective trace module or probe, such as buffer sizes, bus bandwidth or the size of an external probe.

Due to cost savings (no expensive third-party trace hardware required), reduced footprint (very small connectors instead of larger probe connectors), and limited trace bandwidth requirements, the on-chip tracing method is the preferred approach for generating the trace data required for in-depth timing analysis on task, runnable and ISR level. On-chip tracing is a suitable tracing method for devices under test with form factors very close to the final volume production devices.

针对网络协议的模糊测试

网络协议的特点是一般有明确的状态信息,相同的input在不同的状态可能得到不同的output。针对网络协议的模糊测试一般具有stateful的特点。这类模糊测试有几个难点: 1. 生成格式正确的信息,满足对特定状态的fuzz 2. 扩展到不同的协议中 3. 测试样例有效性,需要通过格式校验比如长度、协议认证、校验和等

AFLNET

首次提出针对有状态协议的灰盒模糊测试。AFLNET从响应信息中提取响应码来表示状态信息,并用响应码序列来推断协议实现的状态模型,并进一步使用这一模型来指导fuzz。

一些不足: 1. 状态表示能力:AFLNET要求响应信息中包含状态码,这并不是协议必须实现的。而且状态码表示能力有限,且可能产生冗余状态。 2. 测试效率:没有明确的信号反映待测程序是否处理完消息,因此设置固定的计时器来控制消息发送,时间窗口可能过小或过大。

STATEAFL

使用程序内存状态来表示服务状态,通过对被测程序插桩来收集状态信息并推测状态模型。在每一轮网络交互中,STATEAFL将程序变量值转储给分析队列,并进行post-execution的分析,来更新状态模型。

一些不足: 1. 面对和AFLNET相同的测试效率问题,而且因为后执行分析,产生额外的开销,会降低测试吞吐量。

NSFuzz

使用基于变量的状态表示方法推断状态模型来指导模糊测试,使用基于网络事件循环的同步机制来提高吞吐量。

启发式的变量判断方法:静态分析中只在事件循环代码中分辨状态变量,且关注被读与写、被赋予枚举类型的数据或是数据结构体里的整型成员。

表示状态的方法:使用两条语句维护shared_state数组,当状态变量值被更新时同步更新shared_state;当fuzzer在通信管道收到消息处理结果时,对这个数组进行hash,作为当前程序所处的state。

shared_state[hash(var_id) ^ cur_store_val] = 1;
+      

模糊测试基本介绍

约 1699 个字 2 行代码 预计阅读时间 6 分钟

覆盖率指引的模糊测试方法获得覆盖率的四种追踪方式1

  1. 使用编译器向基本块边缘插桩,可以准确地插桩并易于优化,但需要源码已知。
  2. 静态二进制重写,不需要源码,仍在研究,因为静态代码插桩准确性难以保证,并且优化能力有限。这些限制条件会影响代码率信息的质量与准确性,以及二进制重写的表现。
  3. 动态二进制插桩,不需要源码,可以容易、准确插入代码,但是动态翻译二进制的开销可能大到不能接受。
  4. 硬件辅助追踪,不需要源码,利用内置的硬件追踪扩展,在运行时直接获取控制执行流信息。

侵入式与非侵入式追踪2

Traces can be generated by trace code that is executed within tasks and/or interrupt service routines, just like application code that is executed on the same CPU. This is the most flexible approach, as both the content and the amount of trace information output can be defined in software. However, this tracing method comes with a significant drawback: It uses resources that are shared with the application software, hence tracing may significantly reduce the amount of memory available for the applications, increase the gross execution times of the applications and, in the case of real-time systems, impair functionality. This is why it is called intrusive tracing.

The most common case is that adding trace code is detrimental to the functionality of the applications in real-time systems because the resource requirements for intrusive tracing have been underestimated in the early stages of the project, such that tracing would eventually eat up resources that are required by the application. Therefore, the resource requirements for tracing must be properly considered throughout the whole development lifecycle. Removing trace code from real-time systems may also cause functional issues, typically just before the final production software release. This is the worst case, as trace information is no longer available in this scenario.

Non-intrusive tracing does not change the intrinsic timing behavior of the system under test. This approach simplifies the software development process a lot and requires dedicated hardware support for tracing. External trace probes connected to the target system, in conjunction with on-chip debug modules, capture code execution on instruction level, memory accesses and other events on the target processor. This approach is the best option when it comes to debugging the code execution down to the instruction level. The PCB design of the device under test must provide the connectors required by the external probe.

Another option for non-intrusive tracing is on-chip tracing, where most of the trace hardware is packed into the same chip that also contains the CPU that executes the application code. Non-intrusive tracing can, however, be restricted by limitations of the respective trace module or probe, such as buffer sizes, bus bandwidth or the size of an external probe.

Due to cost savings (no expensive third-party trace hardware required), reduced footprint (very small connectors instead of larger probe connectors), and limited trace bandwidth requirements, the on-chip tracing method is the preferred approach for generating the trace data required for in-depth timing analysis on task, runnable and ISR level. On-chip tracing is a suitable tracing method for devices under test with form factors very close to the final volume production devices.

针对网络协议的模糊测试

网络协议的特点是一般有明确的状态信息,相同的input在不同的状态可能得到不同的output。针对网络协议的模糊测试一般具有stateful的特点。这类模糊测试有几个难点: 1. 生成格式正确的信息,满足对特定状态的fuzz 2. 扩展到不同的协议中 3. 测试样例有效性,需要通过格式校验比如长度、协议认证、校验和等

AFLNET

首次提出针对有状态协议的灰盒模糊测试。AFLNET从响应信息中提取响应码来表示状态信息,并用响应码序列来推断协议实现的状态模型,并进一步使用这一模型来指导fuzz。

一些不足: 1. 状态表示能力:AFLNET要求响应信息中包含状态码,这并不是协议必须实现的。而且状态码表示能力有限,且可能产生冗余状态。 2. 测试效率:没有明确的信号反映待测程序是否处理完消息,因此设置固定的计时器来控制消息发送,时间窗口可能过小或过大。

STATEAFL

使用程序内存状态来表示服务状态,通过对被测程序插桩来收集状态信息并推测状态模型。在每一轮网络交互中,STATEAFL将程序变量值转储给分析队列,并进行post-execution的分析,来更新状态模型。

一些不足: 1. 面对和AFLNET相同的测试效率问题,而且因为后执行分析,产生额外的开销,会降低测试吞吐量。

NSFuzz

使用基于变量的状态表示方法推断状态模型来指导模糊测试,使用基于网络事件循环的同步机制来提高吞吐量。

启发式的变量判断方法:静态分析中只在事件循环代码中分辨状态变量,且关注被读与写、被赋予枚举类型的数据或是数据结构体里的整型成员。

表示状态的方法:使用两条语句维护shared_state数组,当状态变量值被更新时同步更新shared_state;当fuzzer在通信管道收到消息处理结果时,对这个数组进行hash,作为当前程序所处的state。

shared_state[hash(var_id) ^ cur_store_val] = 1;
 shared_state[hash(var_id) ^ pre_store_val] = 0;
 

IoTHunter

提出多阶段信息生成方法来对IoT固件中的有状态网络协议进行fuzz。分为对已知状态的模糊测试与未知状态的探索。基于整数变异的方法改变包类型,并对包格式(比如长度、校验和)做检查等。

数据流指导的模糊测试

控制流指导的模糊测试侧重程序操作的执行顺序(比如分支与循环),数据流指导的模糊测试侧重变量如何定义与使用。变量的定义与使用位置可以不存在控制上的依赖关系。在模糊测试中,数据流主要使用动态污点分析(DTA)技术,即将目标程序的输入数据在定义处视为污点,并在运行时追踪它是如何被访问与使用的。

在实践中,难以做到准确的DTA,开销会很大。并且部分真实程序无法在应用DTA技术的情况下成功编译。因此大部分灰盒模糊测试不使用DTA,以期获得更高的吞吐量。

有一些轻量级的DTA代替方案(比如REDQUEUE、GREYONE),而基于控制流与数据流的模糊测试器的覆盖率指标还没有被完全探索。

DATAFLOW

源码

在程序执行时并行使用数据流分析来指导模糊测试,使用不精确的推断来降低开销并提高吞吐量。对数据流有效性进行了简单的评估,认为对大部分测试目标而言,数据流并不比控制流优越,但是在部分特定场景(比如控制流和语义解耦,如parser)下,数据流可能会有用。


linux内核学习

约 164 个字 2 行代码 预计阅读时间 1 分钟

编译

下载源码,可以从清华源pull一个:git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux.git。随后编译源码,参考CSDN教程。核心逻辑是下载好必要的依赖包(比如apt install build-essential flex bison libssl-dev libelf-dev)之后,在根目录运行make menuconfig,然后Exit保存文件,最后直接多线程编译make -j8

随后是漫长的编译过程。以Linux 6.12-rc6为例可能出现的报错:

证书问题:

make[3]: *** No rule to make target 'debian/canonical-certs.pem', needed by 'certs/x509_certificate_list'.  Stop.
+      

linux内核学习

约 164 个字 2 行代码 预计阅读时间 1 分钟

编译

下载源码,可以从清华源pull一个:git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux.git。随后编译源码,参考CSDN教程。核心逻辑是下载好必要的依赖包(比如apt install build-essential flex bison libssl-dev libelf-dev)之后,在根目录运行make menuconfig,然后Exit保存文件,最后直接多线程编译make -j8

随后是漫长的编译过程。以Linux 6.12-rc6为例可能出现的报错:

证书问题:

make[3]: *** No rule to make target 'debian/canonical-certs.pem', needed by 'certs/x509_certificate_list'.  Stop.
 make[2]: *** [scripts/Makefile.build:478: certs] Error 2
 make[2]: *** Waiting for unfinished jobs....
 
参考StackOverflow上的解答,可以修改conf文件,也可以简单地运行

scripts/config --disable SYSTEM_TRUSTED_KEYS
diff --git a/researching-is-living/related/rca/index.html b/researching-is-living/related/rca/index.html
index d0018c2..c387b56 100644
--- a/researching-is-living/related/rca/index.html
+++ b/researching-is-living/related/rca/index.html
@@ -1,4 +1,4 @@
- 根因分析 - c01dkit's tech blog      

根因分析

约 2291 个字 预计阅读时间 8 分钟

什么是根因分析? 根因分析(Root Cause Analysis)或者说缺陷定位(Fault Localization)是程序开发人员或安全分析人员在确认程序存在异常行为后,通过手动或自动的方法来定位异常行为的根本原因的过程。根因分析是程序安全分析流程中比较重要的一环。

为什么需要设计一些根因分析方法? 在当下各类自动化漏洞挖掘工具(比如各类fuzzer)的辅助下,每日发现的bug数量已经远超开发人员确认并修复的数量。设计一种自动化发现漏洞的工具并不难,难在如何根据这些工具报出的crash信息来准确地分析出漏洞的根本原因。对于大型程序而言,崩溃测试样例(crashing testcase)执行下来可能经历了几百万条汇编指令,手工确认稍微有点不现实了。因此需要设计一些(自动化)的根因分析工具。

怎么进行根因分析?目前有哪些工作? 最朴素而直观的思想就是消耗安全分析人员的精力,从程序的入口点(entry)或者崩溃点(crash site)出发,看看程序是怎么执行的,哪些元素(program entity)会导致最后的crash,然后再进行对应的修复。根据定位元素的粒度不同,根因分析可以定位到函数级(function level)、语句级(statement level)、汇编指令级(instruction level)。由于在汇编指令上进行分析可以更普适地适应多种编程语言、不需要获取源码,所以下文的讨论都是围绕汇编指令级展开。

目前一些自动化根因分析研究思路有:

  1. 基于程序谱的分析方法(Spectrum-based)。大概思路是不需要考虑汇编指令的语义信息,利用一些统计学的方法来分析哪些指令有问题。这类方法基于这样一个场景:假设我们有一大批相似的测试样例,其中有些会导致程序崩溃,有些不会,那么这两类测试样例的执行路径可能有不同的偏好。那么那些更倾向于在崩溃测试样例中执行的指令更有可能是root cause。
  2. 事后分析方法(Postmortem-based)。直译尸检分析,形象理解为从程序崩溃后留下的“尸体”开始分析。它假定程序崩溃后会产生一个coredump(核心转储)文件,包含了崩溃点的内存快照(memory snapshot),以及这个测试样例的执行路径(execution trace)。前者用于提供数据流信息(比如内存值、寄存器值),后者用于提供控制流信息(汇编指令执行与跳转)。在此基础上,结合一些逆向执行(reverse execution)和后向污点分析(backward taint analysis)的方法,定位可能的root cause。
  3. 基于模型的分析方法(Model-based)。这一类方法是近些年提出的,它通过定义语义相关的模型,利用机器学习或深度学习的思想,找到语义上导致崩溃的root cause。

这些研究思路都解决了什么问题?有什么独特的优点?存在哪些独有的不足? 基于程序谱的分析方法直观上似乎有点道理。它仅考虑汇编指令本身,而但仅仅从统计结果上去分析,可能并不能准确分析出逻辑上的root cause。这类方法一般会设计一种排名策略(ranking),对选择出的可疑指令进行top1-topn的排名,来试图提高准确性。这类方法一般需要根据一个崩溃样例以及和它相似的崩溃样例和非崩溃样例进行分析,因此时空开销都比较大。

事后分析方法相比程序谱分析方法考虑了指令语义,比如在逆向执行的时候会设计一些汇编指令handler,对于内存的分析也会更精确些。但污点分析方法毕竟存在过度污染(over-tainting)的问题,导致结果冗余比较严重。

基于模型的分析方法利用AI的优势,可以给出更有语义信息的root cause,在一定程度上帮助开发人员去分析。不过模型的训练依赖训练集的质量,并且受程序语义影响很大。在不同领域之间可能迁移性不是很好,比如没法处理一些特定的密码学函数。且为待测程序建立模型来描述其结构与行为是非常复杂、耗时的事情

现有的这些方法有没有什么普遍存在的问题? 在最后评估阶段(evaluation),一般先通过手工分析确定哪些汇编指令,如果方法输出的汇编指令集合里包含这些指令,那么就认为是发现了root cause。但自动化方法毕竟缺少人工参与,给出的结果一定是不准确的。现有的工作的一个主流思想在于“方法给出的集合可以包含无关指令,但不能缺少相关指令”,旨在提高召回率(recall)。因此往往给出与root cause不相关的指令。但实际上,在最后的修复端,如果给出不相关指令过多,那么仍然需要开发者去分析,依旧耗时耗力。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),9.43%希望root cause在分析结果的Top1,73.58%容许在Top5,15.09%容许在Top10。所以约98%的情况下需要在Top10内给出结果。就分析准确度与开发人员满意度而言,如果RCA工具准确度达90%,满意度几乎达到100%了。准确度低于20%时只有12%接受,如果满意度达50%、75%、90%,准确度需要分别达到50%、75%、85%(但是原文说90%)。

目前的绝大部分RCA分析的工作的输出是两类:ranked list和suspicious set。但两者都存在的问题是仅仅高亮了可能存在bug的元素,而缺乏一些rational的分析。

不同的分析粒度的优势

基于文件粒度的RCA工作(比如Scaffle)希望找到包含百万级同质代码库中哪些文件和crash有关。在此基础上让对应的工程师团队去处理bug,有利于大型组织管理。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),开发者对粒度的top3期望依次是方法级别、语句级别、基本块级别,不过对这三种粒度的倾向之间没有明显差异。而当时比较多的方法是语句级别的

分析时间开销

根据采用的策略不同,RCA之间的时间开销差异可能达两个数量级。(秒级-分钟级-小时级)。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),90%开发者接受1min以内的分析,不到9%开发者接受超过1h的分析。50%开发者大概在30min以内。

一些想法

  1. 什么是漏洞的根本原因?假如函数A内创建临时变量x并调用函数B(x),在B内引发crash,那么应该归咎为A没有处理x呢,还是B没有检查x呢?这是API实现的问题,还是API误用的问题?(开发者or用户)
  2. 对于某一个crash,如果开发人员进行了修复,那么这个修复能拿来当root cause吗?不同开发人员修复的风格可能不一样,修复也未必是完全的,root cause就是一个主观的问题了。

相关论文的一些发现(疑问)

  • “传统的SFL方法效果在Defects4J等部分数据集可能远优于DLFL方法,可能是基准实验的过拟合问题。”传统方法的过拟合指的是什么?DLFL为什么在基准测试集取得和别的数据集一样好的效果?传统方法在不同测试集的表现差异是方法的问题还是测试集的问题?(A Universal Data Augmentation Approach for Fault Localization, ICSE 2022)
  • 不同种类的FL方法在时间开销上数量级是不同的。测试的时候如果集成上较低数量级开销的方法,不会对运行时间有很大影响,但可以提升效率。不同种类FL方法相关性不高,可以考虑结合使用。(An Empirical Study of Fault Localization Families and Their Combinations, TSE 2021)
  • 调用栈做FL分析时,如果根因在栈上的话,40%是第一个栈帧,90%在前10个栈帧里。(Do stack traces help developers fix bugs? Mining Softw. Repositories, 2010)

参考文献

  • Scaffle: Bug Localization on Millions of Files, ISSTA 2020
  • Probabilistic reasoning in diagnosing causes of program failures, STVR 2016
  • Practitioners’ expectations on automated fault localization, ISSTA 2016

以上内容仅代表个人观点,不定期更新,欢迎讨论

根因分析

约 2291 个字 预计阅读时间 8 分钟

什么是根因分析? 根因分析(Root Cause Analysis)或者说缺陷定位(Fault Localization)是程序开发人员或安全分析人员在确认程序存在异常行为后,通过手动或自动的方法来定位异常行为的根本原因的过程。根因分析是程序安全分析流程中比较重要的一环。

为什么需要设计一些根因分析方法? 在当下各类自动化漏洞挖掘工具(比如各类fuzzer)的辅助下,每日发现的bug数量已经远超开发人员确认并修复的数量。设计一种自动化发现漏洞的工具并不难,难在如何根据这些工具报出的crash信息来准确地分析出漏洞的根本原因。对于大型程序而言,崩溃测试样例(crashing testcase)执行下来可能经历了几百万条汇编指令,手工确认稍微有点不现实了。因此需要设计一些(自动化)的根因分析工具。

怎么进行根因分析?目前有哪些工作? 最朴素而直观的思想就是消耗安全分析人员的精力,从程序的入口点(entry)或者崩溃点(crash site)出发,看看程序是怎么执行的,哪些元素(program entity)会导致最后的crash,然后再进行对应的修复。根据定位元素的粒度不同,根因分析可以定位到函数级(function level)、语句级(statement level)、汇编指令级(instruction level)。由于在汇编指令上进行分析可以更普适地适应多种编程语言、不需要获取源码,所以下文的讨论都是围绕汇编指令级展开。

目前一些自动化根因分析研究思路有:

  1. 基于程序谱的分析方法(Spectrum-based)。大概思路是不需要考虑汇编指令的语义信息,利用一些统计学的方法来分析哪些指令有问题。这类方法基于这样一个场景:假设我们有一大批相似的测试样例,其中有些会导致程序崩溃,有些不会,那么这两类测试样例的执行路径可能有不同的偏好。那么那些更倾向于在崩溃测试样例中执行的指令更有可能是root cause。
  2. 事后分析方法(Postmortem-based)。直译尸检分析,形象理解为从程序崩溃后留下的“尸体”开始分析。它假定程序崩溃后会产生一个coredump(核心转储)文件,包含了崩溃点的内存快照(memory snapshot),以及这个测试样例的执行路径(execution trace)。前者用于提供数据流信息(比如内存值、寄存器值),后者用于提供控制流信息(汇编指令执行与跳转)。在此基础上,结合一些逆向执行(reverse execution)和后向污点分析(backward taint analysis)的方法,定位可能的root cause。
  3. 基于模型的分析方法(Model-based)。这一类方法是近些年提出的,它通过定义语义相关的模型,利用机器学习或深度学习的思想,找到语义上导致崩溃的root cause。

这些研究思路都解决了什么问题?有什么独特的优点?存在哪些独有的不足? 基于程序谱的分析方法直观上似乎有点道理。它仅考虑汇编指令本身,而但仅仅从统计结果上去分析,可能并不能准确分析出逻辑上的root cause。这类方法一般会设计一种排名策略(ranking),对选择出的可疑指令进行top1-topn的排名,来试图提高准确性。这类方法一般需要根据一个崩溃样例以及和它相似的崩溃样例和非崩溃样例进行分析,因此时空开销都比较大。

事后分析方法相比程序谱分析方法考虑了指令语义,比如在逆向执行的时候会设计一些汇编指令handler,对于内存的分析也会更精确些。但污点分析方法毕竟存在过度污染(over-tainting)的问题,导致结果冗余比较严重。

基于模型的分析方法利用AI的优势,可以给出更有语义信息的root cause,在一定程度上帮助开发人员去分析。不过模型的训练依赖训练集的质量,并且受程序语义影响很大。在不同领域之间可能迁移性不是很好,比如没法处理一些特定的密码学函数。且为待测程序建立模型来描述其结构与行为是非常复杂、耗时的事情

现有的这些方法有没有什么普遍存在的问题? 在最后评估阶段(evaluation),一般先通过手工分析确定哪些汇编指令,如果方法输出的汇编指令集合里包含这些指令,那么就认为是发现了root cause。但自动化方法毕竟缺少人工参与,给出的结果一定是不准确的。现有的工作的一个主流思想在于“方法给出的集合可以包含无关指令,但不能缺少相关指令”,旨在提高召回率(recall)。因此往往给出与root cause不相关的指令。但实际上,在最后的修复端,如果给出不相关指令过多,那么仍然需要开发者去分析,依旧耗时耗力。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),9.43%希望root cause在分析结果的Top1,73.58%容许在Top5,15.09%容许在Top10。所以约98%的情况下需要在Top10内给出结果。就分析准确度与开发人员满意度而言,如果RCA工具准确度达90%,满意度几乎达到100%了。准确度低于20%时只有12%接受,如果满意度达50%、75%、90%,准确度需要分别达到50%、75%、85%(但是原文说90%)。

目前的绝大部分RCA分析的工作的输出是两类:ranked list和suspicious set。但两者都存在的问题是仅仅高亮了可能存在bug的元素,而缺乏一些rational的分析。

不同的分析粒度的优势

基于文件粒度的RCA工作(比如Scaffle)希望找到包含百万级同质代码库中哪些文件和crash有关。在此基础上让对应的工程师团队去处理bug,有利于大型组织管理。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),开发者对粒度的top3期望依次是方法级别、语句级别、基本块级别,不过对这三种粒度的倾向之间没有明显差异。而当时比较多的方法是语句级别的

分析时间开销

根据采用的策略不同,RCA之间的时间开销差异可能达两个数量级。(秒级-分钟级-小时级)。

据ISSTA 2016一篇调研(Practitioners’ expectations on automated fault localization),90%开发者接受1min以内的分析,不到9%开发者接受超过1h的分析。50%开发者大概在30min以内。

一些想法

  1. 什么是漏洞的根本原因?假如函数A内创建临时变量x并调用函数B(x),在B内引发crash,那么应该归咎为A没有处理x呢,还是B没有检查x呢?这是API实现的问题,还是API误用的问题?(开发者or用户)
  2. 对于某一个crash,如果开发人员进行了修复,那么这个修复能拿来当root cause吗?不同开发人员修复的风格可能不一样,修复也未必是完全的,root cause就是一个主观的问题了。

相关论文的一些发现(疑问)

  • “传统的SFL方法效果在Defects4J等部分数据集可能远优于DLFL方法,可能是基准实验的过拟合问题。”传统方法的过拟合指的是什么?DLFL为什么在基准测试集取得和别的数据集一样好的效果?传统方法在不同测试集的表现差异是方法的问题还是测试集的问题?(A Universal Data Augmentation Approach for Fault Localization, ICSE 2022)
  • 不同种类的FL方法在时间开销上数量级是不同的。测试的时候如果集成上较低数量级开销的方法,不会对运行时间有很大影响,但可以提升效率。不同种类FL方法相关性不高,可以考虑结合使用。(An Empirical Study of Fault Localization Families and Their Combinations, TSE 2021)
  • 调用栈做FL分析时,如果根因在栈上的话,40%是第一个栈帧,90%在前10个栈帧里。(Do stack traces help developers fix bugs? Mining Softw. Repositories, 2010)

参考文献

  • Scaffle: Bug Localization on Millions of Files, ISSTA 2020
  • Probabilistic reasoning in diagnosing causes of program failures, STVR 2016
  • Practitioners’ expectations on automated fault localization, ISSTA 2016

以上内容仅代表个人观点,不定期更新,欢迎讨论

CSE 365 - Spring 2023

约 4823 个字 1287 行代码 预计阅读时间 145 分钟

在终端连接pwn-college时,先在网页端配置下公钥,然后ssh -i 私钥 hacker@dojo.pwn.college即可。网页端启动一个实例后,远程也会自动启动对应的环境。问题一般放在根目录的challenge文件夹下

Talking Web 学习笔记

请求第一行Request line:请求方法 URI 协议版本 CRLF

响应第一行Status line:协议版本 状态码 解释 CRLF

常见的请求方法:

  • GET:获取信息,如果URI是处理程序,则获取程序运行后的结果(而不是源码)
  • HEAD:和GET类似,但是response不返回body,一般用于测试资源是否存在、修改时间,获取资源元数据等
  • POST:提交额外的信息用于服务端处理

HTTP URL Scheme:scheme://host:port/path?query#fragment

  • scheme 访问资源的协议,比如http
  • host 持有资源的主机
  • port 提供服务的程序使用的端口
  • path 确定特定资源
  • query 资源可以利用的额外信息
  • fragment 客户端有关这一资源的信息(不会传给服务器?)

请求的资源含有一些特殊符号比如?,/,&,#等等时,使用%xx进行编码,其中xx是ASCII码。这种做法称为urlencoding

POST请求时,需要带上Content-Type

  • Content-Type: application/x-www-form-urlencoded
  • Content-Type: application/json

前者body里写a=xx,后者写{“a”:”xx”}。json可以构造更复杂的blob

RFC 1945 HTTP协议是无状态的,但是网络应用是有状态的。使用cookie来保持状态。

Assembly Crash Course 学习笔记

Building a Web Server 学习笔记

使用socket创建一个A-B的网络文件,然后使用bind将socket与具体的ip绑定。使用listen来被动侦听sockfd。使用accept接受外部连接。

使用TCP/IP进行网络通讯,服务器端的例子如:

// int socket(int domain, int type, int protocol)
+      

CSE 365 - Spring 2023

约 4823 个字 1287 行代码 预计阅读时间 145 分钟

在终端连接pwn-college时,先在网页端配置下公钥,然后ssh -i 私钥 hacker@dojo.pwn.college即可。网页端启动一个实例后,远程也会自动启动对应的环境。问题一般放在根目录的challenge文件夹下

Talking Web 学习笔记

请求第一行Request line:请求方法 URI 协议版本 CRLF

响应第一行Status line:协议版本 状态码 解释 CRLF

常见的请求方法:

  • GET:获取信息,如果URI是处理程序,则获取程序运行后的结果(而不是源码)
  • HEAD:和GET类似,但是response不返回body,一般用于测试资源是否存在、修改时间,获取资源元数据等
  • POST:提交额外的信息用于服务端处理

HTTP URL Scheme:scheme://host:port/path?query#fragment

  • scheme 访问资源的协议,比如http
  • host 持有资源的主机
  • port 提供服务的程序使用的端口
  • path 确定特定资源
  • query 资源可以利用的额外信息
  • fragment 客户端有关这一资源的信息(不会传给服务器?)

请求的资源含有一些特殊符号比如?,/,&,#等等时,使用%xx进行编码,其中xx是ASCII码。这种做法称为urlencoding

POST请求时,需要带上Content-Type

  • Content-Type: application/x-www-form-urlencoded
  • Content-Type: application/json

前者body里写a=xx,后者写{“a”:”xx”}。json可以构造更复杂的blob

RFC 1945 HTTP协议是无状态的,但是网络应用是有状态的。使用cookie来保持状态。

Assembly Crash Course 学习笔记

Building a Web Server 学习笔记

使用socket创建一个A-B的网络文件,然后使用bind将socket与具体的ip绑定。使用listen来被动侦听sockfd。使用accept接受外部连接。

使用TCP/IP进行网络通讯,服务器端的例子如:

// int socket(int domain, int type, int protocol)
 socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)
 
 // int bind(int sockfd, struct sockaddr* addr, socklen_t addrlen)
diff --git a/software-security/index.html b/software-security/index.html
index f914d89..37db0c5 100644
--- a/software-security/index.html
+++ b/software-security/index.html
@@ -1,4 +1,4 @@
- Index - c01dkit's tech blog     

软件安全

约 68 个字 预计阅读时间不到 1 分钟

Note

有关软件安全的一点笔记,主要包括一点CTF笔记(虽然不是ctfer),以及学习一些程序逆向、程序分析时的一点笔记。

\ No newline at end of file diff --git a/software-security/program-analysis/llvm/index.html b/software-security/program-analysis/llvm/index.html index 4e11631..7b40576 100644 --- a/software-security/program-analysis/llvm/index.html +++ b/software-security/program-analysis/llvm/index.html @@ -1,4 +1,4 @@ - 编译与配置 - c01dkit's tech blog

LLVM 学习

约 1024 个字 173 行代码 预计阅读时间 21 分钟

叠个甲

本文内容是结合ChatGPT-4o-Latest模型、LLVM 15.0.7,在刚接触llvm的时候边学边写下的笔记,可能会出现纰漏。欢迎评论斧正!

快速上手

源码编译

首先在https://github.com/llvm/llvm-project/releases/ 下载心仪的llvm-project-xx.x.x.src.tar.xz,然后tar -xf llvm*解压缩后按如下进行编译:

cd llvm-project-*
+      

LLVM 学习

约 1933 个字 256 行代码 预计阅读时间 32 分钟

叠个甲

本文内容是结合ChatGPT-4o-Latest模型、LLVM 15.0.7,在刚接触llvm的时候边学边写下的笔记,可能会出现纰漏。欢迎评论斧正!

快速上手

源码编译

首先在https://github.com/llvm/llvm-project/releases/ 下载心仪的llvm-project-xx.x.x.src.tar.xz,然后tar -xf llvm*解压缩后按如下进行编译:

cd llvm-project-*
 mkdir build && cd build
 cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS="clang" -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=On -DLLVM_TARGETS_TO_BUILD=host ../llvm
 cmake --build . -j8 # make -j8  根据实际情况选择多线程编译
@@ -93,7 +93,7 @@
 .ll -> .bc: llvm-as a.ll -o a.bc
 .bc -> .ll: llvm-dis a.bc -o a.ll
 .bc -> .s: llc a.bc -o a.s
-

项目例子

利用LLVM构建静态分析框架时,考虑用cmake来组织整个项目的编译。假设需要构建一个程序,它接收一个bc文件名作为参数,然后用两个pass来进行处理,打印出bc文件所包含的函数名,以及函数的参数个数,可以这么来组织项目:

LLVM_BUILD := ~/llvm-project-15.0.7.src/build
+

可视化

opt -p dot-cfg xxx.ll可以将ll文件生成.dot文件,进一步用Graphviz的dot xxx.dot -Tpng -o xxx.png生成CFG图片。

项目例子

利用LLVM构建静态分析框架时,考虑用cmake来组织整个项目的编译。假设需要构建一个程序,它接收一个bc文件名作为参数,然后用两个pass来进行处理,打印出bc文件所包含的函数名,以及函数的参数个数,可以这么来组织项目:

LLVM_BUILD := ~/llvm-project-15.0.7.src/build
 
 # Rule to build the project
 build_project:
@@ -262,503 +262,585 @@
 };
 
 #endif // PRINT_FUNCTION_NAMES_PASS_HPP
-

LLVM IR

opaque pointer

不透明指针即不关心具体的指针类型,而使用ptr来取代之前的具体类型比如i32*。不透明指针在LLVM 15成为默认选项,并在LLVM 17移除透明指针。对于允许禁用不透明指针的LLVM版本而言,在命令行编译时,可以添加-Xclang -no-opaque-pointers来保留显式类型。cmake可以使用-DCLANG_ENABLE_OPAQUE_POINTERS=OFF

在启用不透明指针的情况下,可以在编译时启用-g参数,使得可以从编译器生成的调试信息中恢复出指针的类型信息。

#include<stdio.h>
+

前端分析

clang -Xclang -ast-dump -fsyntax-only sample.c将源码解析为语法树。

LLVM IR

基础指令

sample.c
#include<stdio.h>
 
-struct sample {
-    int x1;
-    int x2;
-    struct sample *next;
-};
-
-void test(int *p, struct sample* s) {
-    s->x2 = *p;
-}
-
-int main () {
-    int a, *p;
-    a = 10;
-    p = &a;
-    struct sample s1;
-    s1.x1 = 20;
-    test(p, &s1);
-    printf("%d",s1.x2 + s1.x1);
-}
-
; ModuleID = 'testsuite/sample1.c'
-source_filename = "testsuite/sample1.c"
+int main() {
+    int a = 1, b = 2;
+    if (a < b)
+    {
+        a = 1;
+    } else {
+        a = 2;
+    }
+
+    return 0;
+}
+

运行clang -S -emit-llvm -O0 test.c -o test.ll后,上述代码生成下列ll文件:

; ModuleID = 'test.c'
+source_filename = "test.c"
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"
 
-%struct.sample = type { i32, i32, ptr }
-
-@.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1
-
-; Function Attrs: noinline nounwind optnone uwtable
-define dso_local void @test(ptr noundef %0, ptr noundef %1) #0 {
-  %3 = alloca ptr, align 8
-  %4 = alloca ptr, align 8
-  store ptr %0, ptr %3, align 8
-  store ptr %1, ptr %4, align 8
-  %5 = load ptr, ptr %3, align 8
-  %6 = load i32, ptr %5, align 4
-  %7 = load ptr, ptr %4, align 8
-  %8 = getelementptr inbounds %struct.sample, ptr %7, i32 0, i32 1
-  store i32 %6, ptr %8, align 4
-  ret void
-}
-
-; Function Attrs: noinline nounwind optnone uwtable
-define dso_local i32 @main() #0 {
-  %1 = alloca i32, align 4
-  %2 = alloca ptr, align 8
-  %3 = alloca %struct.sample, align 8
-  store i32 10, ptr %1, align 4
-  store ptr %1, ptr %2, align 8
-  %4 = getelementptr inbounds %struct.sample, ptr %3, i32 0, i32 0
-  store i32 20, ptr %4, align 8
-  %5 = load ptr, ptr %2, align 8
-  call void @test(ptr noundef %5, ptr noundef %3)
-  %6 = getelementptr inbounds %struct.sample, ptr %3, i32 0, i32 1
-  %7 = load i32, ptr %6, align 4
-  %8 = getelementptr inbounds %struct.sample, ptr %3, i32 0, i32 0
-  %9 = load i32, ptr %8, align 8
-  %10 = add nsw i32 %7, %9
-  %11 = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %10)
-  ret i32 0
-}
-
-declare i32 @printf(ptr noundef, ...) #1
-
-attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4}
-!llvm.ident = !{!5}
-
-!0 = !{i32 1, !"wchar_size", i32 4}
-!1 = !{i32 7, !"PIC Level", i32 2}
-!2 = !{i32 7, !"PIE Level", i32 2}
-!3 = !{i32 7, !"uwtable", i32 2}
-!4 = !{i32 7, !"frame-pointer", i32 2}
-!5 = !{!"clang version 15.0.7"}
-
; ModuleID = 'testsuite/sample1.c'
-source_filename = "testsuite/sample1.c"
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
-%struct.sample = type { i32, i32, %struct.sample* }
-
-@.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1
-
-; Function Attrs: noinline nounwind optnone uwtable
-define dso_local void @test(i32* noundef %0, %struct.sample* noundef %1) #0 {
-  %3 = alloca i32*, align 8
-  %4 = alloca %struct.sample*, align 8
-  store i32* %0, i32** %3, align 8
-  store %struct.sample* %1, %struct.sample** %4, align 8
-  %5 = load i32*, i32** %3, align 8
-  %6 = load i32, i32* %5, align 4
-  %7 = load %struct.sample*, %struct.sample** %4, align 8
-  %8 = getelementptr inbounds %struct.sample, %struct.sample* %7, i32 0, i32 1
-  store i32 %6, i32* %8, align 4
-  ret void
-}
-
-; Function Attrs: noinline nounwind optnone uwtable
-define dso_local i32 @main() #0 {
-  %1 = alloca i32, align 4
-  %2 = alloca i32*, align 8
-  %3 = alloca %struct.sample, align 8
-  store i32 10, i32* %1, align 4
-  store i32* %1, i32** %2, align 8
-  %4 = getelementptr inbounds %struct.sample, %struct.sample* %3, i32 0, i32 0
-  store i32 20, i32* %4, align 8
-  %5 = load i32*, i32** %2, align 8
-  call void @test(i32* noundef %5, %struct.sample* noundef %3)
-  %6 = getelementptr inbounds %struct.sample, %struct.sample* %3, i32 0, i32 1
-  %7 = load i32, i32* %6, align 4
-  %8 = getelementptr inbounds %struct.sample, %struct.sample* %3, i32 0, i32 0
-  %9 = load i32, i32* %8, align 8
-  %10 = add nsw i32 %7, %9
-  %11 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i64 0, i64 0), i32 noundef %10)
-  ret i32 0
-}
-
-declare i32 @printf(i8* noundef, ...) #1
-
-attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4}
-!llvm.ident = !{!5}
-
-!0 = !{i32 1, !"wchar_size", i32 4}
-!1 = !{i32 7, !"PIC Level", i32 2}
-!2 = !{i32 7, !"PIE Level", i32 2}
-!3 = !{i32 7, !"uwtable", i32 2}
-!4 = !{i32 7, !"frame-pointer", i32 2}
-!5 = !{!"clang version 15.0.7"}
-
; ModuleID = 'testsuite/sample1.c'
-source_filename = "testsuite/sample1.c"
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
-%struct.sample = type { i32, i32, ptr }
-
-@.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1, !dbg !0
-
-; Function Attrs: noinline nounwind optnone uwtable
-define dso_local void @test(ptr noundef %0, ptr noundef %1) #0 !dbg !17 {
-  %3 = alloca ptr, align 8
-  %4 = alloca ptr, align 8
-  store ptr %0, ptr %3, align 8
-  call void @llvm.dbg.declare(metadata ptr %3, metadata !29, metadata !DIExpression()), !dbg !30
-  store ptr %1, ptr %4, align 8
-  call void @llvm.dbg.declare(metadata ptr %4, metadata !31, metadata !DIExpression()), !dbg !32
-  %5 = load ptr, ptr %3, align 8, !dbg !33
-  %6 = load i32, ptr %5, align 4, !dbg !34
-  %7 = load ptr, ptr %4, align 8, !dbg !35
-  %8 = getelementptr inbounds %struct.sample, ptr %7, i32 0, i32 1, !dbg !36
-  store i32 %6, ptr %8, align 4, !dbg !37
-  ret void, !dbg !38
-}
-
-; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
-declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
-
-; Function Attrs: noinline nounwind optnone uwtable
-define dso_local i32 @main() #0 !dbg !39 {
-  %1 = alloca i32, align 4
-  %2 = alloca ptr, align 8
-  %3 = alloca %struct.sample, align 8
-  call void @llvm.dbg.declare(metadata ptr %1, metadata !42, metadata !DIExpression()), !dbg !43
-  call void @llvm.dbg.declare(metadata ptr %2, metadata !44, metadata !DIExpression()), !dbg !45
-  store i32 10, ptr %1, align 4, !dbg !46
-  store ptr %1, ptr %2, align 8, !dbg !47
-  call void @llvm.dbg.declare(metadata ptr %3, metadata !48, metadata !DIExpression()), !dbg !49
-  %4 = getelementptr inbounds %struct.sample, ptr %3, i32 0, i32 0, !dbg !50
-  store i32 20, ptr %4, align 8, !dbg !51
-  %5 = load ptr, ptr %2, align 8, !dbg !52
-  call void @test(ptr noundef %5, ptr noundef %3), !dbg !53
-  %6 = getelementptr inbounds %struct.sample, ptr %3, i32 0, i32 1, !dbg !54
-  %7 = load i32, ptr %6, align 4, !dbg !54
-  %8 = getelementptr inbounds %struct.sample, ptr %3, i32 0, i32 0, !dbg !55
-  %9 = load i32, ptr %8, align 8, !dbg !55
-  %10 = add nsw i32 %7, %9, !dbg !56
-  %11 = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %10), !dbg !57
-  ret i32 0, !dbg !58
-}
-
-declare i32 @printf(ptr noundef, ...) #2
-
-attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
-attributes #2 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-
-!llvm.dbg.cu = !{!7}
-!llvm.module.flags = !{!9, !10, !11, !12, !13, !14, !15}
-!llvm.ident = !{!16}
-
-!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
-!1 = distinct !DIGlobalVariable(scope: null, file: !2, line: 20, type: !3, isLocal: true, isDefinition: true)
-!2 = !DIFile(filename: "testsuite/sample1.c", directory: "/home/cby/llm-pca/01-project", checksumkind: CSK_MD5, checksum: "086ff607109bac3c6d0d457996aa6d0d")
-!3 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 24, elements: !5)
-!4 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
-!5 = !{!6}
-!6 = !DISubrange(count: 3)
-!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang version 15.0.7", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !8, splitDebugInlining: false, nameTableKind: None)
-!8 = !{!0}
-!9 = !{i32 7, !"Dwarf Version", i32 5}
-!10 = !{i32 2, !"Debug Info Version", i32 3}
-!11 = !{i32 1, !"wchar_size", i32 4}
-!12 = !{i32 7, !"PIC Level", i32 2}
-!13 = !{i32 7, !"PIE Level", i32 2}
-!14 = !{i32 7, !"uwtable", i32 2}
-!15 = !{i32 7, !"frame-pointer", i32 2}
-!16 = !{!"clang version 15.0.7"}
-!17 = distinct !DISubprogram(name: "test", scope: !2, file: !2, line: 10, type: !18, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !28)
-!18 = !DISubroutineType(types: !19)
-!19 = !{null, !20, !22}
-!20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64)
-!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
-!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sample", file: !2, line: 4, size: 128, elements: !24)
-!24 = !{!25, !26, !27}
-!25 = !DIDerivedType(tag: DW_TAG_member, name: "x1", scope: !23, file: !2, line: 5, baseType: !21, size: 32)
-!26 = !DIDerivedType(tag: DW_TAG_member, name: "x2", scope: !23, file: !2, line: 6, baseType: !21, size: 32, offset: 32)
-!27 = !DIDerivedType(tag: DW_TAG_member, name: "next", scope: !23, file: !2, line: 7, baseType: !22, size: 64, offset: 64)
-!28 = !{}
-!29 = !DILocalVariable(name: "p", arg: 1, scope: !17, file: !2, line: 10, type: !20)
-!30 = !DILocation(line: 10, column: 16, scope: !17)
-!31 = !DILocalVariable(name: "s", arg: 2, scope: !17, file: !2, line: 10, type: !22)
-!32 = !DILocation(line: 10, column: 34, scope: !17)
-!33 = !DILocation(line: 11, column: 14, scope: !17)
-!34 = !DILocation(line: 11, column: 13, scope: !17)
-!35 = !DILocation(line: 11, column: 5, scope: !17)
-!36 = !DILocation(line: 11, column: 8, scope: !17)
-!37 = !DILocation(line: 11, column: 11, scope: !17)
-!38 = !DILocation(line: 12, column: 1, scope: !17)
-!39 = distinct !DISubprogram(name: "main", scope: !2, file: !2, line: 13, type: !40, scopeLine: 13, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !28)
-!40 = !DISubroutineType(types: !41)
-!41 = !{!21}
-!42 = !DILocalVariable(name: "a", scope: !39, file: !2, line: 14, type: !21)
-!43 = !DILocation(line: 14, column: 9, scope: !39)
-!44 = !DILocalVariable(name: "p", scope: !39, file: !2, line: 14, type: !20)
-!45 = !DILocation(line: 14, column: 13, scope: !39)
-!46 = !DILocation(line: 15, column: 7, scope: !39)
-!47 = !DILocation(line: 16, column: 7, scope: !39)
-!48 = !DILocalVariable(name: "s1", scope: !39, file: !2, line: 17, type: !23)
-!49 = !DILocation(line: 17, column: 19, scope: !39)
-!50 = !DILocation(line: 18, column: 8, scope: !39)
-!51 = !DILocation(line: 18, column: 11, scope: !39)
-!52 = !DILocation(line: 19, column: 10, scope: !39)
-!53 = !DILocation(line: 19, column: 5, scope: !39)
-!54 = !DILocation(line: 20, column: 20, scope: !39)
-!55 = !DILocation(line: 20, column: 28, scope: !39)
-!56 = !DILocation(line: 20, column: 23, scope: !39)
-!57 = !DILocation(line: 20, column: 5, scope: !39)
-!58 = !DILocation(line: 21, column: 1, scope: !39)
-
; ModuleID = 'testsuite/sample1.c'
-source_filename = "testsuite/sample1.c"
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
-%struct.sample = type { i32, i32, %struct.sample* }
-
-@.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1, !dbg !0
-
-; Function Attrs: noinline nounwind optnone uwtable
-define dso_local void @test(i32* noundef %0, %struct.sample* noundef %1) #0 !dbg !17 {
-  %3 = alloca i32*, align 8
-  %4 = alloca %struct.sample*, align 8
-  store i32* %0, i32** %3, align 8
-  call void @llvm.dbg.declare(metadata i32** %3, metadata !29, metadata !DIExpression()), !dbg !30
-  store %struct.sample* %1, %struct.sample** %4, align 8
-  call void @llvm.dbg.declare(metadata %struct.sample** %4, metadata !31, metadata !DIExpression()), !dbg !32
-  %5 = load i32*, i32** %3, align 8, !dbg !33
-  %6 = load i32, i32* %5, align 4, !dbg !34
-  %7 = load %struct.sample*, %struct.sample** %4, align 8, !dbg !35
-  %8 = getelementptr inbounds %struct.sample, %struct.sample* %7, i32 0, i32 1, !dbg !36
-  store i32 %6, i32* %8, align 4, !dbg !37
-  ret void, !dbg !38
-}
-
-; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
-declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
-
-; Function Attrs: noinline nounwind optnone uwtable
-define dso_local i32 @main() #0 !dbg !39 {
-  %1 = alloca i32, align 4
-  %2 = alloca i32*, align 8
-  %3 = alloca %struct.sample, align 8
-  call void @llvm.dbg.declare(metadata i32* %1, metadata !42, metadata !DIExpression()), !dbg !43
-  call void @llvm.dbg.declare(metadata i32** %2, metadata !44, metadata !DIExpression()), !dbg !45
-  store i32 10, i32* %1, align 4, !dbg !46
-  store i32* %1, i32** %2, align 8, !dbg !47
-  call void @llvm.dbg.declare(metadata %struct.sample* %3, metadata !48, metadata !DIExpression()), !dbg !49
-  %4 = getelementptr inbounds %struct.sample, %struct.sample* %3, i32 0, i32 0, !dbg !50
-  store i32 20, i32* %4, align 8, !dbg !51
-  %5 = load i32*, i32** %2, align 8, !dbg !52
-  call void @test(i32* noundef %5, %struct.sample* noundef %3), !dbg !53
-  %6 = getelementptr inbounds %struct.sample, %struct.sample* %3, i32 0, i32 1, !dbg !54
-  %7 = load i32, i32* %6, align 4, !dbg !54
-  %8 = getelementptr inbounds %struct.sample, %struct.sample* %3, i32 0, i32 0, !dbg !55
-  %9 = load i32, i32* %8, align 8, !dbg !55
-  %10 = add nsw i32 %7, %9, !dbg !56
-  %11 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i64 0, i64 0), i32 noundef %10), !dbg !57
-  ret i32 0, !dbg !58
-}
-
-declare i32 @printf(i8* noundef, ...) #2
-
-attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
-attributes #2 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-
-!llvm.dbg.cu = !{!7}
-!llvm.module.flags = !{!9, !10, !11, !12, !13, !14, !15}
-!llvm.ident = !{!16}
-
-!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
-!1 = distinct !DIGlobalVariable(scope: null, file: !2, line: 20, type: !3, isLocal: true, isDefinition: true)
-!2 = !DIFile(filename: "testsuite/sample1.c", directory: "/home/cby/llm-pca/01-project", checksumkind: CSK_MD5, checksum: "086ff607109bac3c6d0d457996aa6d0d")
-!3 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 24, elements: !5)
-!4 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
-!5 = !{!6}
-!6 = !DISubrange(count: 3)
-!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang version 15.0.7", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !8, splitDebugInlining: false, nameTableKind: None)
-!8 = !{!0}
-!9 = !{i32 7, !"Dwarf Version", i32 5}
-!10 = !{i32 2, !"Debug Info Version", i32 3}
-!11 = !{i32 1, !"wchar_size", i32 4}
-!12 = !{i32 7, !"PIC Level", i32 2}
-!13 = !{i32 7, !"PIE Level", i32 2}
-!14 = !{i32 7, !"uwtable", i32 2}
-!15 = !{i32 7, !"frame-pointer", i32 2}
-!16 = !{!"clang version 15.0.7"}
-!17 = distinct !DISubprogram(name: "test", scope: !2, file: !2, line: 10, type: !18, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !28)
-!18 = !DISubroutineType(types: !19)
-!19 = !{null, !20, !22}
-!20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64)
-!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64)
-!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sample", file: !2, line: 4, size: 128, elements: !24)
-!24 = !{!25, !26, !27}
-!25 = !DIDerivedType(tag: DW_TAG_member, name: "x1", scope: !23, file: !2, line: 5, baseType: !21, size: 32)
-!26 = !DIDerivedType(tag: DW_TAG_member, name: "x2", scope: !23, file: !2, line: 6, baseType: !21, size: 32, offset: 32)
-!27 = !DIDerivedType(tag: DW_TAG_member, name: "next", scope: !23, file: !2, line: 7, baseType: !22, size: 64, offset: 64)
-!28 = !{}
-!29 = !DILocalVariable(name: "p", arg: 1, scope: !17, file: !2, line: 10, type: !20)
-!30 = !DILocation(line: 10, column: 16, scope: !17)
-!31 = !DILocalVariable(name: "s", arg: 2, scope: !17, file: !2, line: 10, type: !22)
-!32 = !DILocation(line: 10, column: 34, scope: !17)
-!33 = !DILocation(line: 11, column: 14, scope: !17)
-!34 = !DILocation(line: 11, column: 13, scope: !17)
-!35 = !DILocation(line: 11, column: 5, scope: !17)
-!36 = !DILocation(line: 11, column: 8, scope: !17)
-!37 = !DILocation(line: 11, column: 11, scope: !17)
-!38 = !DILocation(line: 12, column: 1, scope: !17)
-!39 = distinct !DISubprogram(name: "main", scope: !2, file: !2, line: 13, type: !40, scopeLine: 13, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !28)
-!40 = !DISubroutineType(types: !41)
-!41 = !{!21}
-!42 = !DILocalVariable(name: "a", scope: !39, file: !2, line: 14, type: !21)
-!43 = !DILocation(line: 14, column: 9, scope: !39)
-!44 = !DILocalVariable(name: "p", scope: !39, file: !2, line: 14, type: !20)
-!45 = !DILocation(line: 14, column: 13, scope: !39)
-!46 = !DILocation(line: 15, column: 7, scope: !39)
-!47 = !DILocation(line: 16, column: 7, scope: !39)
-!48 = !DILocalVariable(name: "s1", scope: !39, file: !2, line: 17, type: !23)
-!49 = !DILocation(line: 17, column: 19, scope: !39)
-!50 = !DILocation(line: 18, column: 8, scope: !39)
-!51 = !DILocation(line: 18, column: 11, scope: !39)
-!52 = !DILocation(line: 19, column: 10, scope: !39)
-!53 = !DILocation(line: 19, column: 5, scope: !39)
-!54 = !DILocation(line: 20, column: 20, scope: !39)
-!55 = !DILocation(line: 20, column: 28, scope: !39)
-!56 = !DILocation(line: 20, column: 23, scope: !39)
-!57 = !DILocation(line: 20, column: 5, scope: !39)
-!58 = !DILocation(line: 21, column: 1, scope: !39)
-

结合调试元数据(如 DILocalVariable 和 DIType)以及高层接口(如函数签名)可以恢复指针类型。但如果没有调试信息,恢复类型会变得困难,只能通过间接手段推断指针类型。

LLVM API

头文件架构

关注之前下载的llvm-project-xx.x.x.src目录下的llvm/include/llvm文件夹,里面包含ADTIRIRReader等各种头文件,从中可以了解如何调API。以15.0.7版本为例,目录架构如下:

tree ./llvm-project-15.0.7.src/llvm/include/llvm -LF 1
./
-├── ADT/
-├── Analysis/
-├── AsmParser/
-├── BinaryFormat/
-├── Bitcode/
-├── Bitstream/
-├── CMakeLists.txt
-├── CodeGen/
-├── Config/
-├── DebugInfo/
-├── Debuginfod/
-├── Demangle/
-├── DWARFLinker/
-├── DWP/
-├── ExecutionEngine/
-├── FileCheck/
-├── Frontend/
-├── FuzzMutate/
-├── InitializePasses.h
-├── InterfaceStub/
-├── IR/
-├── IRReader/
-├── LineEditor/
-├── LinkAllIR.h
-├── LinkAllPasses.h
-├── Linker/
-├── LTO/
-├── MC/
-├── MCA/
-├── module.extern.modulemap
-├── module.install.modulemap
-├── module.modulemap
-├── module.modulemap.build
-├── ObjCopy/
-├── Object/
-├── ObjectYAML/
-├── Option/
-├── PassAnalysisSupport.h
-├── Passes/
-├── Pass.h
-├── PassInfo.h
-├── PassRegistry.h
-├── PassSupport.h
-├── ProfileData/
-├── Remarks/
-├── Support/
-├── TableGen/
-├── Target/
-├── Testing/
-├── TextAPI/
-├── ToolDrivers/
-├── Transforms/
-├── WindowsDriver/
-├── WindowsManifest/
-├── WindowsResource/
-└── XRay/
-
-43 directories, 13 files
-

Pass.h

LLVM Pass的基础是一个个pass,比如自己写一个类继承llvm::ModulePass,在内部覆写runOnModule函数。而ModulePass又是继承自llvm::Pass的,也就是直接来自头文件目录下的Pass.h文件。这个头文件大致结构如下:

Pass.h
#ifndef LLVM_PASS_H
-#define LLVM_PASS_H
-#include <string>
-
-namespace llvm {
-
-class AnalysisResolver;
-class AnalysisUsage;
-class Function;
-//   ...
-
-// AnalysisID - Use the PassInfo to identify a pass...
-using AnalysisID = const void *;
-
-/// Different types of internal pass managers.
-enum PassManagerType {
-//   ...
-};
-
-// Different types of passes.
-enum PassKind {
-//   ...
-};
-
-/// This enumerates the LLVM full LTO or ThinLTO optimization phases.
-enum class ThinOrFullLTOPhase {
-//   ...
-};
-
-class Pass {
-// ...
-};
-
-class ModulePass : public Pass {
-// ...
-};
-
-class ImmutablePass : public ModulePass {
-// ...
-};
-
-class FunctionPass : public Pass {
-// ...
-};
-
-} // end namespace llvm
-
-// Include support files that contain important APIs commonly used by Passes,
-// but that we want to separate out to make it easier to read the header files.
-#include "llvm/PassAnalysisSupport.h"
-#include "llvm/PassSupport.h"
-
-#endif // LLVM_PASS_H
-

可见,ModulePass和FunctionPass两个类直接继承了Pass。ImmutablePass直接继承了ModulePass。

bc文件读取与解析

通过#include "llvm/IRReader/IRReader.h"使用std::unique_ptr<Module> parseIRFile(StringRef Filename, SMDiagnostic &Err, LLVMContext &Context)来获取bc文件的指针,随后可以在自定义方法如myParseFunc(const Module &Mod)中遍历指针内容(即解引用),得到llvm::Module下一层的llvm::Function。类似地,对llvm::Function进一步遍历可以获取llvm::BasicBlock,再进一步遍历可以获取llvm::Instruction,每一级可以调用相关API函数。

四大关键程序对象

根据LLVM分析的程序对象不同,可以按从大到小的顺序分为Module、Function、BasicBlock、Instruction四个等级。可以直接采用for循环遍历高等级对象的方法,获取其中的下一级对象。可见前文的项目例子。

llvm::Module

可以理解为对整个bc文件进行分析得到的结果,其中包含多个Function。

llvm::Function

llvm::BasicBlock

const llvm::BasicBlock BB;
-BB.getTerminator(); // 获取基本块最后一条指令
-

llvm::Instruction

const llvm::Instruction I;
-I.getOpcodeName(); // 获取操作符的字符串名称
-I.getNumOperands(); // 获取操作数个数
-I.getOperand(i); // 获取第i个操作数,返回llvm::Value*
-
-I.hasMetaData(); // 检查当前指令是否附有metadata,比如调试信息
-I.getMetaData("dbg"); // 获取当前指令的dbg调试信息
-

调试信息分析

前文提到,在编译程序时添加-g选项,可以生成类似

IDA使用

约 112 个字 预计阅读时间不到 1 分钟

反编译ARM raw binary

加载时选择Processor type,比如ARM Little-endian [ARM],随后根据实际加载情况设置ROM的起始地址和Input file地址。

raw binary的前四字节可能是初始sp值,随后四字节可能是初始pc值。按G并输入pc值,Alt+G设置T寄存器值为1(0表示ARM,1表示Thumb),然后选中pc及之后所有代码,按C进行MakeCode。

IDA使用

约 112 个字 预计阅读时间不到 1 分钟

反编译ARM raw binary

加载时选择Processor type,比如ARM Little-endian [ARM],随后根据实际加载情况设置ROM的起始地址和Input file地址。

raw binary的前四字节可能是初始sp值,随后四字节可能是初始pc值。按G并输入pc值,Alt+G设置T寄存器值为1(0表示ARM,1表示Thumb),然后选中pc及之后所有代码,按C进行MakeCode。

\ No newline at end of file diff --git a/software-security/reverse/index.html b/software-security/reverse/index.html new file mode 100644 index 0000000..a7a2c14 --- /dev/null +++ b/software-security/reverse/index.html @@ -0,0 +1,107 @@ + Index - c01dkit's tech blog

Index

约 0 个字 预计阅读时间不到 1 分钟

\ No newline at end of file diff --git a/software-security/reverse/reverse-advanced/index.html b/software-security/reverse/reverse-advanced/index.html index 8d1fe17..e92ba2c 100644 --- a/software-security/reverse/reverse-advanced/index.html +++ b/software-security/reverse/reverse-advanced/index.html @@ -1,4 +1,4 @@ - 逆向高阶 - c01dkit's tech blog

逆向高阶

约 59 个字 预计阅读时间不到 1 分钟

Windows逆向技术概念

DLL注入,Windows消息钩取,DLL卸载,代码注入,API钩取,进程隐藏,IE连接控制,TLS回调函数,TEB,PEB,SEH,IA-32,反调试(静态、动态),PE镜像,Debug Blocker

逆向高阶

约 59 个字 预计阅读时间不到 1 分钟

Windows逆向技术概念

DLL注入,Windows消息钩取,DLL卸载,代码注入,API钩取,进程隐藏,IE连接控制,TLS回调函数,TEB,PEB,SEH,IA-32,反调试(静态、动态),PE镜像,Debug Blocker

逆向基础

约 1078 个字 10 行代码 预计阅读时间 5 分钟

逆向函数时,要提前预测下函数实现机制,以节省时间。要明白哪些部分属于程序特有的实现,哪些部分属于第三方的库,不要随便进到第三方库或者底层API里面分析。

调用约定

cdecl(C默认)由caller负责清理栈上传入参数。

stdcall由callee负责清理栈上传入参数(Win32API),被调函数返回时使用RETN X来退出,相当于RETN、POP X。比如退两个参数,就RETN 8。

fastcall为了提高速度,分别使用ECX、EDX传递前两个参数,更多参数还是使用内存。 传参时都是从右向左以此压入栈中。

一些常见汇编操作符

call 包括保存返回地址、IP跳转

retnpop EIP

test 相当于AND,但是不改变普通寄存器的值,只修改EFLAGS寄存器

NOP指令的用途

NOP指令通常用于控制时序的目的,强制内存对齐,防止流水线灾难,占据分支指令延迟,或是作为占位符以供程序的改善(或替代被移除的指令)。

函数执行栈帧推断

函数内部一般先会执行以下两条指令:

push ebp
+      

逆向基础

约 1078 个字 10 行代码 预计阅读时间 5 分钟

逆向函数时,要提前预测下函数实现机制,以节省时间。要明白哪些部分属于程序特有的实现,哪些部分属于第三方的库,不要随便进到第三方库或者底层API里面分析。

调用约定

cdecl(C默认)由caller负责清理栈上传入参数。

stdcall由callee负责清理栈上传入参数(Win32API),被调函数返回时使用RETN X来退出,相当于RETN、POP X。比如退两个参数,就RETN 8。

fastcall为了提高速度,分别使用ECX、EDX传递前两个参数,更多参数还是使用内存。 传参时都是从右向左以此压入栈中。

一些常见汇编操作符

call 包括保存返回地址、IP跳转

retnpop EIP

test 相当于AND,但是不改变普通寄存器的值,只修改EFLAGS寄存器

NOP指令的用途

NOP指令通常用于控制时序的目的,强制内存对齐,防止流水线灾难,占据分支指令延迟,或是作为占位符以供程序的改善(或替代被移除的指令)。

函数执行栈帧推断

函数内部一般先会执行以下两条指令:

push ebp
 mov ebp,esp
 

可以观察ebp和esp的修改情况推断函数栈帧

名称修饰

名称修饰(name mangling,name decoration),用来解决标志符的唯一命名问题。比如在不同的命名空间实现相同名称的函数,这个函数在怎么表示呢?名称修饰技术用来生成唯一的标志符,保留命名空间、函数名、结构体名、类名以及参数类型等等信息。名称修饰和调用约定、编译器有关,应用最广泛的是C++的代码(尤其是混合C编译时)。比如_ZN9wikipedia7article6formatEv可以用来表示:

namespace wikipedia
 {