不定期更新

两个linux文件互传

1
$ scp -r linux-2.6.26 root@(目标ip)IP:/usr/src/(假设放到/usr/src路径)

文件查找

将当前目录及其子目录下所有文件后缀为 .c 的文件列出来:

1
$ find . -name "*.c"

find默认不查找软链接的文件夹, 所以, 可以加-L解决这个问题, 这个很重要!!!!!!

将一个本地程序做成一个本地服务程序

1
$ socat tcp-l:2333,reuseaddr,fork exec:./pwn1

服务端口在2333,使用nc 127.0.0.1 2333连接

获取ubuntu当前内核的源码

进入lauchpad, 分清你的系统名称, 比如 20.04 叫 Focal Fossa, 系统当前版本:

1
2
$ uname -r
5.13.0-35-generic

那么我们在页面的以下部分会看到以下部分的内容

Active series and milestones

点击其中的focal series, 会出现搜索框, 我们就搜索linux-image-5.13.0-35-generic, 会得到如下几个结果:

1
2
3
4
5
6
7
8
9
10
11
12
 linux-image-5.13.0-35-generic: <<<<<<<<<<<<<<<<<<<<<<<
Signed kernel image generic
linux-image-5.13.0-35-generic-dbgsym:
Signed kernel image generic
linux-image-5.13.0-35-generic-lpae:
Linux kernel image for version 5.13.0 on ARM (hard float) SMP
linux-image-5.13.0-35-generic-lpae-dbgsym:
Linux kernel debug image for version 5.13.0 on ARM (hard float) SMP
linux-image-5.13.0-35-generic-64k:
Signed kernel image generic-64k
linux-image-5.13.0-35-generic-64k-dbgsym:
Signed kernel image generic-64k

选择第一个, 出现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Signed kernel image generic
A kernel image for generic. This version of it is signed with
Canonical's UEFI/Opal signing key.

Source package
linux-signed-hwe-5.13 5.13.0-35.40~20.04.1 source package in Ubuntu <<<<<<<<<<<<<<<

Published versions
linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in amd64 (Updates)
linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in amd64 (Security)
linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in arm64 (Updates)
linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in arm64 (Security)
linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in armhf (Updates)
linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in armhf (Security)
linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in ppc64el (Updates)
linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in ppc64el (Security)
linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in s390x (Updates)
linux-image-5.13.0-35-generic 5.13.0-35.40~20.04.1 in s390x (Security)

此处我选Source package下的链接. 之后选择downloads里的tar.xz文件即可.

这个版本的文件里包含的是一个下载脚本, 并没有包含完整的src文件. 所以还是需要想想其它办法直接获得文件最好.

快速转换图片格式,修改分辨率

1
2
$ convert -resize 100x100 src.jpg dst.jpg
$ convert -resize 50%x50% src.jpg dst.jpg

修改文件的用户

1
2
3
4
5
6
7
8
查看归属:
$ ls -l file

赋给用户hv
$ chown hv:hv file

如果需要把某个文件夹下所有都付给某个用户
$ chown hv:hv -R dir/*

使用audit记录创建的程序

audit是记录linux审计信息的内核模块。
他记录系统中的各种动作和事件,比如系统调用,文件修改,执行的程序,系统登入登出和记录所有系统中所有的事件。audit还可以将审计记录写入日志文件。

如果想记录新创建的process, 可以直接修改/etc/audit/audit.rules, 添加一行-a task,always, 之后通过cat /var/log/audit/audit.log|grep EXECVE 来筛选你想要的记录.

比如

1
2
$ auditctl -a exit,always -F arch=b64 -S execve 添加execve检测
$ auditctl -D 删除所有规则

更多可以参考linux监控工具audit

修改terminal的显示路径

1
$ vim ~/.bashrc

找到

1
2
3
4
## If this is an xterm set the title to user@host:dir
case “$TERM” in
xterm|rxvt)
PS1=”\e]0;$debianchroot:+($debianchroot)\u@\h:\w\a$PS1”

将PS1那行修改为(其实就是把w换成W)

1
PS1=”[\u@\h:\W]\\$”

添加环境变量

1
export PATH=$PATH:/home/victorv

创建terminal的快捷键

如果是在kali,terminal是没有快捷键的,到设置的keyboard里面,添加自定义快捷键,键值为

1
gnome-terminal

或者安装nautilus-open-terminal

gdb改变汇编代码显示方式

1
(gdb) set disas intel

设置反汇编代码使用的指令集,可选择 intel 指令集或 AT&T指令集.

usb驱动相关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
查找usb驱动
$ sudo lspci

02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8111/8168B PCI Express Gigabit Ethernet controller (rev 01)
$ find /sys | grep drivers.*02:00

获取usb设备信息
lsusb -t
cat /proc/bus/usb/devices
lshw

卸载usb驱动
tree /sys/bus/usb/drivers
echo -n “1-1:1.0” > /sys/bus/usb/drivers/ub/unbind

centos安装内核header

1
yum install kernel-devel-$(uname -r) kernel-headers-$(uname -r)

如果遇到没有搜索结果, 可以做如下操作:

  1. 查看当前版本
    1
    2
    [root@centos~]# cat /etc/redhat-release
    CentOS Linux release 7.4.1708 (Core)
  2. 修改文件/etc/yum.repos.d/CentOS-Vault.repo, 添加当前版本的以下信息:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    [C(Your Version Number)-base] 比如 [C5.6-base]
    name=CentOS-(Your Version Number) - Base
    baseurl=http://vault.centos.org/(Your Version Number)/os/$basearch/
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5
    enabled=1

    [C(Your Version Number-updates]
    name=CentOS-(Your Version Number) - Updates
    baseurl=http://vault.centos.org/(Your Version Number)/updates/$basearch/
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5
    enabled=1

    示例:
    [C7.4.1708-base]
    name=CentOS-7.4.1708 - Base
    baseurl=https://vault.centos.org/7.4.1708/os/$basearch/
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
    enabled=1

    [C7.4.1708-updates]
    name=CentOS-7.4.1708 - Updates
    baseurl=https://vault.centos.org/7.4.1708/updates/$basearch/
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
    enabled=1

之后再试一次install即可.

更多参考Finding Old kernel-devel Packages For CentOS

添加sudoer 并且取消密码

1
2
superuser ALL=(ALL) NOPASSWD:ALL
superuser ALL=(ALL:ALL) ALL #不取消密码

创建ssh服务

1
2
3
4
5
$ yum -y install openssh-server openssh-clients
$ chkconfig sshd on
$ service sshd start
$ netstat -tulpn | grep :22
$ vi /etc/sysconfig/iptables -A RH-Firewall-1-INPUT -m state –state NEW -m tcp -p tcp –dport 22 -j ACCEPT

创建ftp 服务

1
2
3
sudo yum install vsftpd
sudo service vsftpd restart
chkconfig vsftpd on

ubuntu修改内核调试启动项

1
vi /etc/default/grub

在屁股后面添加 kgdboc=ttyS1,115200

1
2
grep menu /boot/grub/grub.cfg
grub-reboot ‘1>3’

第一个数字1代表第二行的submenu,第二个3代表submenu的第四个(从0开始)

挂起一个进程

ctrl+z
fg 恢复

打包、解压文件

解包使用x,打包使用c

tar.xz
解包:tar zxvf file.tar.xz 或者:xz -d file.tar.xz && tar xvf file.tar
打包:tar zcvf file.tar.xz

.tar
解包:tar xvf FileName.tar
打包:tar cvf FileName.tar DirName
(注:tar是打包,不是压缩!)
———————————————
.gz
解压1:gunzip FileName.gz
解压2:gzip -d FileName.gz
压缩:gzip FileName

.tar.gz 和 .tgz
解压:tar zxvf FileName.tar.gz
压缩:tar zcvf FileName.tar.gz DirName
———————————————
.bz2
解压1:bzip2 -d FileName.bz2
解压2:bunzip2 FileName.bz2
压缩: bzip2 -z FileName

.tar.bz2
解压:tar jxvf FileName.tar.bz2
压缩:tar jcvf FileName.tar.bz2 DirName
———————————————
.bz
解压1:bzip2 -d FileName.bz
解压2:bunzip2 FileName.bz
压缩:未知

.tar.bz
解压:tar jxvf FileName.tar.bz
压缩:未知
———————————————
.Z
解压:uncompress FileName.Z
压缩:compress FileName
.tar.Z

解压:tar Zxvf FileName.tar.Z
压缩:tar Zcvf FileName.tar.Z DirName
———————————————
.zip
解压:unzip FileName.zip
压缩:zip FileName.zip DirName
———————————————
.rar
解压:rar x FileName.rar
压缩:rar a FileName.rar DirName
———————————————
.lha
解压:lha -e FileName.lha
压缩:lha -a FileName.lha FileName
———————————————
.rpm
解包:rpm2cpio FileName.rpm | cpio -div
———————————————
.deb
解包:ar p FileName.deb data.tar.gz | tar zxf -
———————————————
.tar .tgz .tar.gz .tar.Z .tar.bz .tar.bz2 .zip .cpio .rpm .deb .slp .arj .rar .ace .lha .lzh .lzx .lzs .arc .sda .sfx .lnx .zoo .cab .kar .cpt .pit .sit .sea
解压:sEx x FileName.*
压缩:sEx a FileName.* FileName

单独重新编译一个内核模块

当我们想修改内核某个模块,又不想重新make all的时候,可以这样操作.

1
make drivers/net/ethernet/intel/e1000/e1000.ko

或者

1
make drivers/net/ethernet/intel/e1000/

gcc 汇编

1
2
3
4
5
.intel_syntax noprefix # intel 汇编格式
xor eax, eax

.att_syntax prefix # att汇编格式
movl %adx, %eax…

一个简单的 t.s 文件:

1
2
3
4
5
6
7
8
9
10
11
.intel_syntax noprefix
.global test # 声明函数
.global g_var # 声明全局变量

.text # 以下是.text段
test:
mov qword ptr[g_var], 12
ret

.data # 以下是.data段
g_var: .quad 0 # 初始化变量为 0

t.c:

1
2
3
4
5
6
7
#include <stdio.h>
int test(void);
extern long g_var;
void main(void){
test();
printf("%d\n", g_var);
}

如果是t.cpp, 记得使用extern "C" int test(void);

编译链接:

1
2
gcc -c t.s
gcc t.c t.o -o tt2

如果是编写so文件, 记得在Makefile的命令中添加-fstack-protector-all, 否则, 会有个execute stack的flag在里面, 导致dlopen失败.

更多参考GNU assembler, How do I compile the asm generated by GCC?, GNU Assembler Examples

编写linux驱动与汇编相关的tips

如果想给驱动内联一个汇编文件的函数, 可以如下:

Makefile:

1
2
3
4
5
6
7
8
9
10
obj-m += Anyname.o
KDIR:=/lib/modules/$(shell uname -r)/build
MAKE:=make
Anyname-objs := main.o test.o
CFLAGS_main.o := -D_FORTIFY_SOURCE=0 -O0

default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean

main.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <linux/module.h> 
#include <asm/io.h>
#include <linux/slab.h>
#include <linux/ioport.h>
MODULE_LICENSE("GPL");

int test(void);
int test2(void);
int my_module_init(void){
printk("module init done\n");
printk("test:%d, %d\n", test(), test2());
return 0;
}

void my_module_exit(void){
printk("module exit\n");
return;
}

module_init( my_module_init );//声明初始化函数
module_exit( my_module_exit );

test.S: 这里后缀必须是大写的S, 额外的格式参考arch/x86/net/bpf_jit.S

1
2
3
4
5
6
7
8
9
10
11
.intel_syntax noprefix #声明 intel 格式
.text # 声明 .text 字段
.global test # 声明函数
test:
mov rax,12
ret

.global test2 # 声明函数
test2:
mov rax, 8
ret

如果想禁止gcc编译的驱动给某个函数优化, 可以使用void __attribute__((optimize("O0"))) test(void), 这样这个函数就不会被优化了.

也可以采取如下方式:

1
2
3
4
5
6
7
#pragma GCC push_options
#pragma GCC optimize("O0")
void test(void){
int i=0;
return i+1;
}
#pragma GCC pop_options

额外的tips, 如果存在if(var&0x80000000)这样的操作, var一定不要用int类型, 要用无符号! gcc会把判断直接优化成0!!!!!!!!

gcc 内联汇编语法示例

1
2
3
4
5
6
7
8
9
 __asm__ ("movl %eax, %ebx\n\t"
"movq %%rax,%%rdx\n\t" // 64bit operation
"movl %ecx, $label(%edx,%ebx,$4)\n\t"
"movb %ah, (%ebx)");
asm ( assembler template
: output operands /* optional */
: input operands /* optional */
: list of clobbered registers /* optional */
);
1
2
3
4
5
6
7
int a=10, b;
asm ("movl %1, %%eax;
movl %%eax, %0;"
:"=r"(b) /* output */
:"r"(a) /* input */
:"%eax" /* clobbered register */
);

“=r”(b) 的含义, 将输出放入倒变量b里(%0 代表第一个变量, 此处第一个变量是输出里的b, 所以%0就是b, %1是 a). r代表使用任意寄存器, 如果是其它寄存器, 参考如下:

1
2
3
4
5
6
7
8
9
10
+---+--------------------+
| r | Register(s) |
+---+--------------------+
| a | %eax, %ax, %al |
| b | %ebx, %bx, %bl |
| c | %ecx, %cx, %cl |
| d | %edx, %dx, %dl |
| S | %esi, %si |
| D | %edi, %di |
+---+--------------------+

如果是使用内存, 用 m.

其它指示标识:

  1. “m” : A memory operand is allowed, with any kind of address that the machine supports in general.
  2. “o” : A memory operand is allowed, but only if the address is offsettable. ie, adding a small offset to the address gives a valid address.
  3. “V” : A memory operand that is not offsettable. In other words, anything that would fit the m’ constraint but not the o’constraint.
  4. “i” : An immediate integer operand (one with constant value) is allowed. This includes symbolic constants whose values will be known only at assembly time.
  5. “n” : An immediate integer operand with a known numeric value is allowed. Many systems cannot support assembly-time constants for operands less than a word wide. Constraints for these operands should use ’n’ rather than ’i’.
  6. “g” : Any register, memory or immediate integer operand is allowed, except for registers that are not general registers.

x86指令独有:

1
2
3
4
5
6
7
8
9
10
11
12
1. "r" : Register operand constraint, look table given above.
2. "q" : Registers a, b, c or d.
3. "I" : Constant in range 0 to 31 (for 32-bit shifts).
4. "J" : Constant in range 0 to 63 (for 64-bit shifts).
5. "K" : 0xff.
6. "L" : 0xffff.
7. "M" : 0, 1, 2, or 3 (shifts for lea instruction).
8. "N" : Constant in range 0 to 255 (for out instruction).
9. "f" : Floating point register
10. "t" : First (top of stack) floating point register
11. "u" : Second floating point register
12. "A" : Specifies the `a’ or `d’ registers. This is primarily useful for 64-bit integer values intended to be returned with the `d’ register holding the most significant bits and the `a’ register holding the least significant bits.

特殊符合含义:

  1. =“ : 将结果写入到指定位置
  2. &“ : Means that this operand is an earlyclobber operand, which is modified before the instruction is finished using the input operands. Therefore, this operand may not lie in a register that is used as an input operand or as part of any memory address. An input operand can be tied to an earlyclobber operand if its only use as an input occurs before the early result is written.

示例:

1
2
3
4
5
6
7
8
9
10
11
12
static inline char * strcpy(char * dest,const char *src)
{
int d0, d1, d2;
__asm__ __volatile__( "1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
: "=&S" (d0), "=&D" (d1), "=&a" (d2)
: "0" (src),"1" (dest)
: "memory");
return dest;
}

当我们不希望编译器优化掉我们的某些特殊循环判断时:

1
2
3
4
asm ("l1:\tmovb (%0), %%al\n\t"
"cmp $0xcc, %%al\n\t"
"je l1"
::"r"(&buffer[0x7f]));

禁用gcc的某个函数优化

1
2
3
4
5
6
#pragma GCC push_options
#pragma GCC optimize("O0")
void test(int a);
return a;
}
#pragma GCC pop_options

更多参考GCC-Inline-Assembly-HOWTO

log至文件中

有时候看不到printf, 需要log到文件里, 就经常需要查阅怎么写, 比较烦人. 记录一下.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
int sl(char* str){
int len = 0;
while(*str++){
len++;
}
return len;
}

void log2file(char *fmt, ...){
va_list args;
va_start(args, fmt);
char str[0x200];
// 请自己确保log的内容不超过0x200.
vsprintf(str, fmt, args);
va_end(args);
int fd;
fd = open("/tmp/mylog.log", O_CREAT|O_WRONLY|O_APPEND, 0777);
if(fd == -1){
printf("create fail\n");
fd = open("/tmp/mylog.log", O_WRONLY|O_APPEND, 0777);
if(fd==-1) {
char str2[0x200];
sprintf(str2, "echo \"%s\"> /tmp/mylog.log", str);
system(str2);
return;
}
}
printf("write\n");
write(fd, str, sl(str));
close(fd);
}
void main(){
log2file("hello:%x\n", 0x111231);
}

centos7 代理yum

1
2
3
yum install epel-release -y
rpm -ivh https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
yum install -y proxychains-ng

修改配置vi /etc/proxychains.conf:

1
2
3
4
5
[ProxyList]
# add proxy here ...
# meanwile
# defaults set to "tor"
socks5 192.168.150.1 7890

代理yum

1
$> proxychains4 yum install bpftrace

Centos6 国内源

因为centos6.x停止维护了, 所以要找个能用的源很麻烦, 偶尔要设置又容易忘了, 在此记录一下

  1. 下载

    1
    wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-6.10.repo
  2. 编辑/etc/yum.repos.d/CentOS-Base.repo, 在vim里更改版本 :%s/6.10/6.8/g

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    # CentOS-Base.repo

    [base]
    name=CentOS-vault-6.10 - Base - mirrors.aliyun.com
    failovermethod=priority
    baseurl=http://mirrors.aliyun.com/centos-vault/6.10/os/$basearch/
    http://mirrors.aliyuncs.com/centos-vault/6.10/os/$basearch/
    http://mirrors.cloud.aliyuncs.com/centos-vault/6.10/os/$basearch/
    gpgcheck=1
    gpgkey=http://mirrors.aliyun.com/centos-vault/RPM-GPG-KEY-CentOS-6

    #released updates
    [updates]
    name=CentOS-vault-6.10 - Updates - mirrors.aliyun.com
    failovermethod=priority
    baseurl=http://mirrors.aliyun.com/centos-vault/6.10/updates/$basearch/
    http://mirrors.aliyuncs.com/centos-vault/6.10/updates/$basearch/
    http://mirrors.cloud.aliyuncs.com/centos-vault/6.10/updates/$basearch/
    gpgcheck=1
    gpgkey=http://mirrors.aliyun.com/centos-vault/RPM-GPG-KEY-CentOS-6

    #additional packages that may be useful
    [extras]
    name=CentOS-vault-6.10 - Extras - mirrors.aliyun.com
    failovermethod=priority
    baseurl=http://mirrors.aliyun.com/centos-vault/6.10/extras/$basearch/
    http://mirrors.aliyuncs.com/centos-vault/6.10/extras/$basearch/
    http://mirrors.cloud.aliyuncs.com/centos-vault/6.10/extras/$basearch/
    gpgcheck=1
    gpgkey=http://mirrors.aliyun.com/centos-vault/RPM-GPG-KEY-CentOS-6

    #additional packages that extend functionality of existing packages
    [centosplus]
    name=CentOS-vault-6.10 - Plus - mirrors.aliyun.com
    failovermethod=priority
    baseurl=http://mirrors.aliyun.com/centos-vault/6.10/centosplus/$basearch/
    http://mirrors.aliyuncs.com/centos-vault/6.10/centosplus/$basearch/
    http://mirrors.cloud.aliyuncs.com/centos-vault/6.10/centosplus/$basearch/
    gpgcheck=1
    enabled=0
    gpgkey=http://mirrors.aliyun.com/centos-vault/RPM-GPG-KEY-CentOS-6

    #contrib - packages by Centos Users
    [contrib]
    name=CentOS-vault-6.10 - Contrib - mirrors.aliyun.com
    failovermethod=priority
    baseurl=http://mirrors.aliyun.com/centos-vault/6.10/contrib/$basearch/
    http://mirrors.aliyuncs.com/centos-vault/6.10/contrib/$basearch/
    http://mirrors.cloud.aliyuncs.com/centos-vault/6.10/contrib/$basearch/
    gpgcheck=1
    enabled=0
    gpgkey=http://mirrors.aliyun.com/centos-vault/RPM-GPG-KEY-CentOS-6

    如果是centos7的, 记得还需要改RPM-GPG-KEY-CentOS-6RPM-GPG-KEY-CentOS-7

接着:yum clean all, yum makecahe.

Centos 7.5更新7.9

  1. 下载centos 7.9的ISO 下载链接
  2. 把文件拷贝进去
  3. 挂载iso
    1
    2
    $ mkdir /mnt/cdrom
    $ mount ./CentOS-7-x86_64-DVD-2009.iso /mnt/cdrom
  4. 更改源 /etc/yum.repo.d/CentOS-Media.repo
    1
    2
    3
    4
    5
    6
    [c7-media]
    name=CentOS Media
    baseurl=file:///mnt/cdrom/
    gpgcheck=1
    enabled=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
  5. 更新yum --disablerepo=* --enablerepo=c7-media update

Centos 6.x 安装python2.7

  1. yum install openssl-devel
  2. 下载源码: python 2.7.13源码, 解压源码tar Jxf Python-2.7.13.tar.xz
  3. ./configure --prefix=/usr/local/python27 --enable-shared
  4. make && make install, ln -s /usr/local/python27/bin/python /usr/bin/python27
  5. echo "/usr/loca/python27/lib" >>/etc/ld.so.conf, 执行ldconfig
  6. 直接运行python27, 如果正常运行就ok.

bash 语法

引用命令行参数

直接引用

$1,$2….
如果超过9, ${10}
${1:-8} 如果不存在1位置的变量, 默认给8
${parameter:?word} 可以默认给字符串

flags

​```bash
while getopts u:a:f: flag#选项后面的冒号表示该选项需要参数
do
case “${flag}” in
u) username=${OPTARG};;#参数存在$OPTARG中
a) age=${OPTARG};;
f) fullname=${OPTARG};;
esac
done
echo “Username: $username”;
echo “Age: $age”;
echo “Full Name: $fullname”;

1
2
3
4
5
6
7
8
9
10
11
12
13
14

`sh userReg-flags.sh -f 'John Smith' -a 25 -u john `

getopts,它不支持长选项。 $OPTIND 表示当前argv索引位置.

**$@**

​```bash
i=1;
for user in "$@"
do
echo "Username - $i: $user";
i=$((i + 1));
done

$* :和$@相同,但”$*“ 和 “$@”(加引号)并不同,”$*“将所有的参数解释成一个字符串,而”$@”是一个参数数组

shift operator

1
2
3
4
5
6
7
8
i=1;
j=$#;# $#是参数个数
while [ $i -le $j ]
do
echo "Username - $i: $1";
i=$((i + 1));
shift 1; #移动默认的argv的索引. 此处移1位, $1就变了
done

if

1
2
3
4
5
6
7
if commands; then
commands
[elif commands; then
commands...]
[else
commands]
fi
Operation Effect
[ ! EXPR ] True if EXPR is false.
[ ( EXPR ) ] Returns the value of EXPR. This may be used to override the normal precedence of operators.
[ EXPR1 -a EXPR2 ] True if both EXPR1 and EXPR2 are true.
[ EXPR1 -o EXPR2 ] True if either EXPR1 or EXPR2 is true.
[ -a FILE ] True if FILE exists.
[ -b FILE ] True if FILE exists and is a block-special file.
[ -c FILE ] True if FILE exists and is a character-special file.
[ -d FILE ] True if FILE exists and is a directory.
[ -e FILE ] True if FILE exists.
[ -f FILE ] True if FILE exists and is a regular file.
[ -g FILE ] True if FILE exists and its SGID bit is set.
[ -h FILE ] True if FILE exists and is a symbolic link.
[ -k FILE ] True if FILE exists and its sticky bit is set.
[ -p FILE ] True if FILE exists and is a named pipe (FIFO).
[ -r FILE ] True if FILE exists and is readable.
[ -s FILE ] True if FILE exists and has a size greater than zero.
[ -t FD ] True if file descriptor FD is open and refers to a terminal.
[ -u FILE ] True if FILE exists and its SUID (set user ID) bit is set.
[ -w FILE ] True if FILE exists and is writable.
[ -x FILE ] True if FILE exists and is executable.
[ -O FILE ] True if FILE exists and is owned by the effective user ID.
[ -G FILE ] True if FILE exists and is owned by the effective group ID.
[ -L FILE ] True if FILE exists and is a symbolic link.
[ -N FILE ] True if FILE exists and has been modified since it was last read.
[ -S FILE ] True if FILE exists and is a socket.
[ FILE1 -nt FILE2 ] True if FILE1 has been changed more recently than FILE2, or if FILE1 exists and FILE2 does not.
[ FILE1 -ot FILE2 ] True if FILE1 is older than FILE2, or is FILE2 exists and FILE1 does not.
[ FILE1 -ef FILE2 ] True if FILE1 and FILE2 refer to the same device and inode numbers.
[ -o OPTIONNAME ] True if shell option “OPTIONNAME” is enabled.
[ -z STRING ] True of the length if “STRING” is zero.
[ -n STRING ] or [ STRING ] True if the length of “STRING” is non-zero.
[ STRING1 == STRING2 ] True if the strings are equal. “=” may be used instead of “==” for strict POSIX compliance.
[ STRING1 != STRING2 ] True if the strings are not equal.
[ STRING1 < STRING2 ] True if “STRING1” sorts before “STRING2” lexicographically in the current locale.
[ STRING1 > STRING2 ] True if “STRING1” sorts after “STRING2” lexicographically in the current locale.
[ ARG1 OP ARG2 ] “OP” is one of -eq, -ne, -lt, -le, -gt or -ge. These arithmetic binary operators return true if “ARG1” is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to “ARG2”, respectively. “ARG1” and “ARG2” are integers.

编译Gnutls

基于Centos7

gntls下载libnettlegmplib

  1. 先编译gmplib, 安装后, export GMP_CFLAGS="-I/usr/local/include" GMP_LIBS="-L/usr/local/lib -lgmp"
  2. 编译安装nettle, ./configure --prefix=/usr --enable-static --enable-mini-gmp
  3. export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/:/usr/local/lib/pkgconfig/ 设置pkg-config的查找路径
  4. 设置lib路径, 编辑/etc/ld.so.conf, 添加一行/usr/local/lib, 执行ldconfig -v
  5. 编译gnutls: ./configure --without-p11-kit

主要参考

编译samba最新版

在安装好gnutls后, 安装需要的组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ yum install python36-dns
$ yum install python36-markdown
$ yum install perl
$ yum -y install perl-CPAN
$ yum -y install popt-devel
$ perl -MCPAN -e 'install JSON'
To install modules, you need to configure a local Perl library directory or
escalate your privileges. CPAN can help you by bootstrapping the local::lib
module or by configuring itself to use 'sudo' (if available). You may also
resolve this problem manually if you need to customize your setup.

What approach do you want? (Choose 'local::lib', 'sudo' or 'manual')
[local::lib] <<<<<<<<<<<<<<<<<<< 输入enter

Autoconfigured everything but 'urllist'.

Now you need to choose your CPAN mirror sites. You can let me
pick mirrors for you, you can select them from a list or you
can enter them by hand.

Would you like me to automatically choose some CPAN mirror
sites for you? (This means connecting to the Internet) [yes] no <<<<<<<<<<<<<<<<<<< 输入no

Would you like to pick from the CPAN mirror list? [yes] no <<<<<<<<<<<<<<<<<<< 输入no
Now you can enter your own CPAN URLs by hand. A local CPAN mirror can be
listed using a 'file:' URL like 'file:///path/to/cpan/'

CPAN.pm needs at least one URL where it can fetch CPAN files from.

Please enter your CPAN site: [] http://mirrors.ustc.edu.cn/CPAN/ <<<<<<<<<<<<<<<<<<< 输入这个网址, 配置国内的源

上面的组件安装完成后, 就可以配置编译了:

./configure --enable-debug --prefix=/home/vv/install-smb-4.17.2 --with-shared-modules='!vfs_snapper'

Linux Ptrace的权限问题

如果想避免同用户使用ptrace调试, 可以设置prctl(PR_SET_DUMPABLE, 1LL, 0LL, 0LL, 0LL) , 参考

与之相关的还有/proc/sys/kernel/yama/ptrace_scope, 这个也影响了ptrace的使用.

OpenSSL技巧

如果想修改原始的send数据, SSL_CTX_set_msg_callback(ctx, message_cb);, 这个回调就是在send前触发.

如果想发送任意的加密数据, 可以使用ssl->method->ssl_write_bytes(ssl, SSL3_RT_ALERT, data, data_length, &written); 去发送.

dtls server示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <time.h>

#pragma warning(disable:4996)
#define PSK_KEY "Key"
#define PSK_IDENTITY "Ide"
#pragma comment(lib,"libcrypto.lib")
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"ws2_32.lib")

struct ssl_st {
/*
* protocol version (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION,
* DTLS1_VERSION)
*/
int version;
/* SSLv3 */
const SSL_METHOD* method;
};

const struct ssl_method_st // 通过逆向FireDaemon OpenSSL 3\bin\libcrypto-3-x64.dll得到的, 只针对sslv3, openssl的版本会有不同.
{
int version;
unsigned int flags;
unsigned int mask;
int(__fastcall* ssl_new)(ssl_st*);
int(__fastcall* ssl_clear)(ssl_st*);
void(__fastcall* ssl_free)(ssl_st*);
int(__fastcall* ssl_accept)(ssl_st*);
int(__fastcall* ssl_connect)(ssl_st*);
int(__fastcall* ssl_read)(ssl_st*, void*, unsigned __int64, unsigned __int64*);
int(__fastcall* ssl_peek)(ssl_st*, void*, unsigned __int64, unsigned __int64*);
int(__fastcall* ssl_write)(ssl_st*, const void*, unsigned __int64, unsigned __int64*);
int(__fastcall* ssl_shutdown)(ssl_st*);
int(__fastcall* ssl_renegotiate)(ssl_st*);
int(__fastcall* ssl_renegotiate_check)(ssl_st*, int);
int(__fastcall* ssl_read_bytes)(ssl_st*, int, int*, unsigned __int8*, unsigned __int64, int, unsigned __int64*);
int(__fastcall* ssl_write_bytes)(ssl_st*, int, const void*, unsigned __int64, unsigned __int64*);
int(__fastcall* ssl_dispatch_alert)(ssl_st*);
};


int generate_cookie(SSL* ssl, unsigned char* cookie, unsigned int* cookie_len)
{
/* Generate a cookie */
int i;

/* Seed the random number generator */
srand(time(NULL));

/* Generate a random cookie */
for (i = 0; i < 16; i++)
cookie[i] = rand() % 256;

/* Print the cookie */
printf("Cookie: ");
for (i = 0; i < 16; i++)
printf("%02X", cookie[i]);
printf("\n");
*cookie_len = 16;
return 1;
}

int verify_cookie(SSL* ssl, const unsigned char* cookie, unsigned int cookie_len)
{
/* Verify the cookie */
/* ... */

return 1;
}

static unsigned int psk_server_cb(SSL* ssl, const char* identity,
unsigned char* psk, unsigned int max_psk_len)
{
if (strcmp(identity, PSK_IDENTITY) != 0)
{
printf("Unknown PSK identity\n");
return 0;
}

if (strlen(PSK_KEY) > max_psk_len)
{
printf("PSK key is too long\n");
return 0;
}

memcpy(psk, PSK_KEY, strlen(PSK_KEY)+1);
return strlen(PSK_KEY);
}

void print_memory(const void* mem, size_t len) {
const unsigned char* p = (const unsigned char*)mem;
for (size_t i = 0; i < len; i += 16) {
printf("%08zx ", i);
for (size_t j = 0; j < 16; j++) {
if (i + j < len) {
printf("%02x ", p[i + j]);
}
else {
printf(" ");
}
}
printf(" ");
for (size_t j = 0; j < 16; j++) {
if (i + j < len) {
printf("%c", isprint(p[i + j]) ? p[i + j] : '.');
}
}
printf("\n");
}
}

//void message_cb(int write_p, int version,
// int content_type, const void* buf,
// size_t len, SSL* ssl, void* arg) {
// printf("-------------dump memory------------------\n");
// print_memory(buf, len);
// printf("-------------dump done====================\n");
//}

int g_need_change = 0;
long send_callback(BIO* bio, int cmd, const char* argp, int argi,
long argl, long ret) {
if (cmd == BIO_CB_WRITE) {
if (g_need_change) {
char* data = (char*)argp;
*data = 21;// NX_SECURE_TLS_ALERT
}
}
return ret;
}

#pragma pack(push,1)
void handle_lwm2m_protocol(SSL* ssl) {
char* buffer = (char*)calloc(1, 0x1000);
char* data = buffer;
int data_length = 0;
unsigned long long written = 0;

data = buffer;
*(data) = 0;// not NX_SECURE_TLS_ALERT_LEVEL_WARNING
*(data + 1) = 1;// not NX_SECURE_TLS_ALERT_CLOSE_NOTIFY
data_length = 2;

ssl->method->ssl_write_bytes(ssl, SSL3_RT_ALERT, data, data_length, &written);

//SSL_read(ssl, buffer, 0x1000);
Sleep(1000);

struct coap_header {
char token_length : 4;
char type : 4;
char code;
short id;// ´ó¶ËÐò

} *header;
header = (struct coap_header *)buffer;
header->type = 4;// NX_LWM2M_CLIENT_COAP_VERSION_1
header->code = 2; // NX_LWM2M_CLIENT_COAP_REQUEST_POST

// ±ä³¤µÄ½á¹¹Ìå coap option header
data = buffer + 4;
*(unsigned char*)data = (11<<4)|(2);// 11:NX_LWM2M_CLIENT_COAP_OPTION_URI_PATH, 2 for value length
*(data + 1) = 'b';
*(data + 2) = 's';
*(unsigned char*)(data+3) = 0xff;// 0xff:NX_LWM2M_CLIENT_COAP_PAYLOAD_MARKER, for NX_LWM2M_CLIENT_COAP_OPTION_NONE;
data_length = 4 + 4;
SSL_write(ssl, buffer, data_length);

//SSL_read(ssl, buffer, 0x1000);

data = buffer;
*(data) = 0;// not NX_SECURE_TLS_ALERT_LEVEL_WARNING
*(data + 1) = 1;// not NX_SECURE_TLS_ALERT_CLOSE_NOTIFY
data_length = 2;
ssl->method->ssl_write_bytes(ssl, SSL3_RT_ALERT, data, data_length, &written);
}
#pragma pack(pop)

int main(int argc, char** argv)
{
SSL_CTX* ctx;
SSL* ssl;
BIO* bio;
int ret;

/* Initialize OpenSSL */
SSL_library_init();
SSL_load_error_strings();
int iResult;
WSADATA wsaData;

// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed: %d\n", iResult);
return 1;
}

/* Create a new DTLS context */
ctx = SSL_CTX_new(DTLSv1_2_server_method());
if (ctx == NULL)
{
printf("Error creating DTLS context\n");
return -1;
}

/* Set the PSK callback */
SSL_CTX_set_psk_server_callback(ctx, psk_server_cb);

//SSL_CTX_set_msg_callback(ctx, message_cb);

/* Set the cipher list to include only PSK-AES128-CCM8 */
if (SSL_CTX_set_cipher_list(ctx, "PSK-AES128-CCM8") != 1)
{
printf("Error setting cipher list\n");
return -1;
}

/* Create a new socket */
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
printf("Error creating socket\n");
return -1;
}

/* Bind the socket to the specified port */
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(5784);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
printf("Error binding socket, %d\n", GetLastError());
WSACleanup();
return -1;
}

/* Create a new DTLS connection */
bio = BIO_new_dgram(sock, BIO_NOCLOSE);
if (bio == NULL)
{
printf("Error creating DTLS connection\n");
WSACleanup();
return -1;
}

ssl = SSL_new(ctx);
if (ssl == NULL)
{
printf("Error creating DTLS connection\n");
WSACleanup();
return -1;
}

SSL_set_bio(ssl, bio, bio);

/* Set the DTLS cookie generation and verification callbacks */
SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie);
SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie);

//BIO_set_callback(bio, send_callback);


/* Wait for a DTLS client to connect */
struct sockaddr_storage client_addr = { 0 };
printf("Waiting for DTLS client to connect...\n");
do {
ret = DTLSv1_listen(ssl, (BIO_ADDR *) & client_addr);
if (ret == -1) {
printf("Error: %s\n", ERR_error_string(ERR_get_error(), NULL));
}
} while (ret <= 0);

/* Perform the DTLS handshake */
printf("Performing DTLS handshake...\n");
if (SSL_accept(ssl) <= 0)
{
printf("Error performing DTLS handshake\n");
WSACleanup();
return -1;
}

printf("DTLS handshake complete\n");

/* Communicate with the DTLS client */
/* ... */

handle_lwm2m_protocol(ssl);

/* Clean up */
SSL_free(ssl);
SSL_CTX_free(ctx);

return 0;
}

openssl renegotiate

当完成tls握手后, 如果你想触发renegotiate操作, 可以如下操作:

1
2
3
4
5
6
7
int ret = SSL_renegotiate(ssl);
if (ret) {
ret = SSL_do_handshake(ssl);// 发送 hello request请求
if (ret) {
SSL_read(ssl, buffer, 1024);// 如果目标发的消息没有处理完, 不会进行握手
}
}

SSL_renegotiate 设置重协商标志, SSL_do_handshake 发送加密的hello request请求. 如果client正常处理, 就应该返回一个加密的hello消息. 后续, 调用SSL_read 来触发新的握手协商. 需要注意的时, 如果连接里有未读取的数据, 需要读到client回执的hello消息时才会触发握手操作!

如果只是想简单测试, 可以用openssl程序实现, 下面的命令加载一个openssl server, 读取密钥和证书, 监听443.

1
2
3
4
> openssl.exe s_server -accept 443 -cert D:\tmp\cert.pem -key D:\tmp\key.pem
Using default temp DH parameters
ACCEPT

输入r然后按Enter, 就可以让server给client发送重协商操作.

参考:

tls重协商攻击

An Introduction to OpenSSL Programming, Part II of II, 这个文章很老旧了, 代码会有不对的地方.

schannel renegotiate的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
int Renegotiation(SOCKET Server_Socket) {
TimeStamp Lifetime;
SecBufferDesc OutBuffDesc;
SecBuffer OutSecBuff[2];
SecBufferDesc InBuffDesc;
SecBuffer InSecBuff[2];
ULONG Attribs = 0;
SECURITY_STATUS Status;

int cbIn = 0;

SecBufferDesc OutBuffer;
SecBuffer OutBuffers[1];
DWORD dwSSPIFlags;
DWORD dwSSPIOutFlags;

//DWORD dwType = SCHANNEL_RENEGOTIATE;

//OutBuffers[0].pvBuffer = &dwType;
//OutBuffers[0].BufferType = SECBUFFER_TOKEN;
//OutBuffers[0].cbBuffer = sizeof(dwType);

//OutBuffer.cBuffers = 1;
//OutBuffer.pBuffers = OutBuffers;
//OutBuffer.ulVersion = SECBUFFER_VERSION;

//Status = ApplyControlToken(&hctxt, &OutBuffer);
//if (FAILED(Status)) {
// SetLastError(Status);
// LogError("fail to get controll data");
// return 0;
//}

dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
ASC_REQ_REPLAY_DETECT |
ASC_REQ_CONFIDENTIALITY |
ASC_REQ_EXTENDED_ERROR |
ASC_REQ_ALLOCATE_MEMORY |
ASC_REQ_STREAM;

InSecBuff[0].BufferType = SECBUFFER_EMPTY;
InSecBuff[0].pvBuffer = NULL;
InSecBuff[0].cbBuffer = 0;

InBuffDesc.ulVersion = SECBUFFER_VERSION;
InBuffDesc.cBuffers = 1;
InBuffDesc.pBuffers = InSecBuff;

OutBuffers[0].BufferType = SECBUFFER_TOKEN;
OutBuffers[0].pvBuffer = NULL;
OutBuffers[0].cbBuffer = 0;

OutBuffer.ulVersion = SECBUFFER_VERSION;
OutBuffer.cBuffers = 1;
OutBuffer.pBuffers = OutBuffers;

Status = AcceptSecurityContext(
&hcred,
&hctxt,
&InBuffDesc,
dwSSPIFlags,
SECURITY_NATIVE_DREP,
NULL,
&OutBuffer,
&dwSSPIOutFlags,
&Lifetime);
if (FAILED(Status)) {
SetLastError(Status);
LogError("fail to get hello");
return 0;
}
// 发送hello request 给client, client解密后会是SEC_I_RENEGOTIATE, 会调用InitializeSecurityContext, 然后发送消息过来
if (!SendBytes(
Server_Socket,
(BYTE*)(OutBuffers[0].pvBuffer),
OutBuffers[0].cbBuffer))
{
printf("send message failed. \n");
}

if (!ReceiveMsg(// 接收client发来的加密hello消息
Server_Socket,
g_pInBuf,
g_cbMaxMessage,
&cbIn))
{
return(FALSE);
}

SecBuffer security_buffers[4] = { 0 };
SecBufferDesc security_buffers_desc;
security_buffers[0].BufferType = SECBUFFER_DATA;
security_buffers[0].pvBuffer = g_pInBuf;
security_buffers[0].cbBuffer = cbIn;
security_buffers[1].BufferType = SECBUFFER_EMPTY;
security_buffers[2].BufferType = SECBUFFER_EMPTY;
security_buffers[3].BufferType = SECBUFFER_EMPTY;

security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]);
security_buffers_desc.pBuffers = security_buffers;
security_buffers_desc.ulVersion = SECBUFFER_VERSION;

Status = DecryptMessage(&hctxt, &security_buffers_desc, 0, NULL);

if (Status != SEC_I_RENEGOTIATE) {// 解密后应该是SEC_I_RENEGOTIATE消息
return 0;
}
SecBuffer* pDataBuffer = NULL;
SecBuffer* pExtraBuffer = NULL;
for (int i = 1; i < 4; i++) {
if (pDataBuffer == NULL && security_buffers[i].BufferType == SECBUFFER_DATA) {
pDataBuffer = &security_buffers[i];
}
if (pExtraBuffer == NULL && security_buffers[i].BufferType == SECBUFFER_EXTRA) {
pExtraBuffer = &security_buffers[i];
}
}
//----------------------------------------------------------------
// Prepare output buffers.

OutBuffDesc.ulVersion = SECBUFFER_VERSION;
OutBuffDesc.cBuffers = 1;
OutBuffDesc.pBuffers = OutSecBuff;

OutSecBuff[0].cbBuffer = 0;
OutSecBuff[0].BufferType = SECBUFFER_TOKEN;
OutSecBuff[0].pvBuffer = NULL;

//OutSecBuff[1].cbBuffer = 0;
//OutSecBuff[1].BufferType = SECBUFFER_EMPTY;
//OutSecBuff[1].pvBuffer = NULL;

//----------------------------------------------------------------
// Prepare input buffers.

InBuffDesc.ulVersion = SECBUFFER_VERSION;
InBuffDesc.cBuffers = 2;
InBuffDesc.pBuffers = InSecBuff;

InSecBuff[0].cbBuffer = pExtraBuffer->cbBuffer;
InSecBuff[0].BufferType = SECBUFFER_TOKEN;
InSecBuff[0].pvBuffer = pExtraBuffer->pvBuffer;
InSecBuff[1].cbBuffer = 0;
InSecBuff[1].BufferType = SECBUFFER_EMPTY;
InSecBuff[1].pvBuffer = NULL;

printf("Token buffer received (%lu bytes):\n", InSecBuff[0].cbBuffer);
PrintHexDump(InSecBuff[0].cbBuffer, (PBYTE)InSecBuff[0].pvBuffer);

Status = AcceptSecurityContext(
&hcred,
&hctxt,
&InBuffDesc,
dwSSPIFlags,
SECURITY_NATIVE_DREP,// not used according doc
&hctxt,
&OutBuffDesc,
&dwSSPIFlags,
&Lifetime);
// 这里会出错, 不清楚原因.
if (Status & 0x80000000) {
LogError("fail to say hello");
return 0;
}
......

这段代码应该是这么写的, 但是我自己跑的时候, 在第二次的AcceptSecurityContext会遇到解密错误, 暂时不清楚原因, 但是网络上又找不到相关的实现做一个参考, 所以列出来希望对人有帮助.

参考:

Schannel and Session Renegotiation

Renegotiating an Schannel Connection

cmake

获取某个git项目下的依赖git项目: git submodule update --init --recursive

cmake -DXXXX=ON ./ 表示开启XXXX特性, 生成makefile. XXXX特性由CMakeLists.txt定义, 形式如下:

1
option(suppress_header_searches "do not try to find headers - used when compiler check will fail" OFF)

表示接受参数-Dsuppress_header_searches=ON, 默认是OFF.

生成makefile后, 执行cmake --build .编译