安全矩阵

 找回密码
 立即注册
搜索
楼主: Grav1ty

郑嘉源的学习日记

[复制链接]

180

主题

231

帖子

1178

积分

金牌会员

Rank: 6Rank: 6

积分
1178
 楼主| 发表于 2022-6-2 00:03:29 | 显示全部楼层
SHELL编程备忘



if判断:

[ -a FILE ]        如果 FILE 存在则为真
[ -b FILE ]        如果 FILE 存在且是一个块特殊文件则为真
[ -c FILE ]        如果 FILE 存在且是一个字符特殊文件则为真
[ -e FILE ]        如果 FILE 存在则为真
[ -f FILE ]        如果 FILE 存在且是一个普通文件则为真
[ -g FILE ]        如果 FILE 存在且已经设置了SGID则为真
[ -h FILE ]        如果 FILE 存在且是一个符号连接则为真
[ -k FILE ]        如果 FILE 存在且已经设置了粘制位则为真
[ -r FILE ]        如果 FILE 存在且是可读的则为真
[ -s FILE ]        如果 FILE 存在且大小不为0则为真
[ -t FD ]           如果文件描述符 FD 打开且指向一个终端则为真
[ -u FILE ]        如果 FILE 存在且设置了SUID (set user ID)则为真
[ -w FILE ]        如果 FILE 如果 FILE 存在且是可写的则为真
[ -x FILE ]        如果 FILE 存在且是可执行的则为真
[ -O FILE ]       如果 FILE 存在且属有效用户ID则为真
[ - G FILE ]       如果 FILE 存在且属有效用户组则为真
[ -L FILE ]        如果 FILE 存在且是一个符号连接则为真
[ -N FILE ]        如果 FILE 存在 and has been mod如果ied since it was last read则为真
[ -S FILE ]        如果 FILE 存在且是一个套接字则为真
[ -z STRING ] “STRING” 的长度为零则为真






字符串判断

str1 = str2两个字符串完全相等为真
str1 != str2两个字符串不完全相等为真
-n str1当串的长度大于0时为真(串非空)
-z str1当串的长度为0时为真(空串)
str1当串str1为非空时为真






数字判断

int1 -eq int2        两数字相等为真
int1 -ne int2        两数字不相等为真
int1 -gt int2        int1大于int2为真
int1 -ge int2        int1>= int2为真
in1 -lt int2        int1<int2 为真
int1 -le int2        int1 <= int2为真






文件判断

-r file         用户可读为真
-w file        用户可写为真
-f file         文件为正规文件为真
-x file        用户可执行为真
-d file        文件为目录为真
-c file        存在且是特殊字符文件为真
-s file        文件大小非0为真
-b file        文件为块特殊文件为真
-t file         文件描述符(默认1)指定的设备为终端时为真





回复

使用道具 举报

180

主题

231

帖子

1178

积分

金牌会员

Rank: 6Rank: 6

积分
1178
 楼主| 发表于 2022-6-5 20:59:37 | 显示全部楼层
本帖最后由 Grav1ty 于 2022-11-12 23:30 编辑

[持续更新]

RAX,EAX,AX,AH,AL关系

|63..32|31..16|15-8|7-0|
                       |AH|AL|
                       |AX.....|
           |EAX................|
|RAX...........................|
gdb常用命令手册(见附件)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

180

主题

231

帖子

1178

积分

金牌会员

Rank: 6Rank: 6

积分
1178
 楼主| 发表于 2022-10-29 00:28:04 | 显示全部楼层
驱动1


first.c
  1. #include<ntddk.h>

  2. VOID DriverUnload() {
  3.         DbgPrint("first: Our driver is Unloading... \r\n");
  4. }

  5. NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) {
  6.         DbgPrint("first : hello ,my salary!\r\n");
  7.         driver->DriverUnload = DriverUnload;
  8.         return STATUS_SUCCESS;
  9. }
复制代码
makefile
  1. !IF 0

  2. Copyright (C) Microsoft Corporation, 1999 - 2002

  3. Module Name:

  4.     makefile.

  5. Notes:

  6.     DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
  7.     file to this component.  This file merely indirects to the real make file
  8.     that is shared by all the components of Windows NT (DDK)

  9. !ENDIF

  10. !INCLUDE $(NTMAKEENV)\makefile.def
复制代码
sources(这里纠个错,很多书里写是SOURCE,但source没用,会报错“BUILD: Computing Include file dependencies:”)

  1. TARGETNAME=Frist
  2. TARGETPATH=Release
  3. TARGETTYPE=DRIVER

  4. SOURCES=first.c
复制代码


下载WDK7600,build在.\release\ia64下生成:



加载sys需要用到


步骤:









然后打开dbgview



启动试试



回复

使用道具 举报

180

主题

231

帖子

1178

积分

金牌会员

Rank: 6Rank: 6

积分
1178
 楼主| 发表于 2022-10-29 01:10:41 | 显示全部楼层
本帖最后由 Grav1ty 于 2022-10-29 01:26 编辑

驱动2

串口过滤

大概逻辑:创建虚拟设备(IoCreateDevice)->绑定到真实对象上(IoAttachDeviceToDeviceStack)->分发函数(ccpDispatch)->如果irpsp.MajorFunction是写,则捕获,获取缓冲区及其长度并打印,否则直接放行->动态卸载

用到的重要库中函数:
  1. NTSTATUS IoAttachDeviceToDeviceStackSafe(
  2.   [in]  PDEVICE_OBJECT SourceDevice, //过滤设备
  3.   [in]  PDEVICE_OBJECT TargetDevice,  //要被绑定的设备栈中的设备
  4.   [out] PDEVICE_OBJECT *AttachedToDeviceObject  //返回最终被绑定的设备
  5. );
复制代码
  1. NTSTATUS IoCreateDevice(
  2.   [in]           PDRIVER_OBJECT  DriverObject, //本驱动的驱动对象,由系统给
  3.   [in]           ULONG           DeviceExtensionSize, //设备拓展,此处填0
  4.   [in, optional] PUNICODE_STRING DeviceName,  //设备名称(过滤设备一般不需要名称,故此处填null)
  5.   [in]           DEVICE_TYPE     DeviceType,  //设备类型,填被绑定的设备类型即可
  6.   [in]           ULONG           DeviceCharacteristics,  //设备特征,生成设备对象时一般为0
  7.   [in]           BOOLEAN         Exclusive,
  8.   [out]          PDEVICE_OBJECT  *DeviceObject
  9. );
复制代码
  1. //通过设备名字获取设备对象
复制代码
不知道为什么这个函数在代码块中显示不出来,那就放在正文里
//通过设备名字获取设备对象
NTSTATUS IoGetDeviceObjectPointer(
  [in]  PUNICODE_STRING ObjectName,  //传入设备名称
  [in]  ACCESS_MASK     DesiredAccess,  //期望的权限 直接FILE_ALL_ACCESS即可
  [out] PFILE_OBJECT    *FileObject,  //返回设备对象的同时会返回一个文件对象
  [out] PDEVICE_OBJECT  *DeviceObject  //返回的文件对象
);

  1. void IoSkipCurrentIrpStackLocation(
  2.   [in, out] PIRP Irp
  3. );  //跳过当前栈空间
复制代码
  1. NTSTATUS IofCallDriver(
  2.   PDEVICE_OBJECT        DeviceObject,  //接收irp的设备
  3.   __drv_aliasesMem PIRP Irp  //要发送的irp
  4. );  //把irp发给设备的函数
复制代码

irp结构中有三个地方描述缓冲区:
irp->MDLAddress  比较简单且不追求效率的情况,把R3的缓冲数据拷贝到内核空间
irp->UserBuffer  最追求效率的方案,应用层的缓冲区地址直接放在UserBuffer里,在内核空间中访问
irp->AssociatedIrp.SystemBuffer  把应用层的地址空间映射到内核空间,MDL翻译为“内存描述符链”。irp中的MDLAddress是一个MDL指针,这个MDL可以读出一个内存空间的虚拟地址,这就弥补了UserBuffer的不足,同时比SystemBuffer更轻量

获取缓冲区有多长,对于此处遇到的情况而言:
  1. ULONG len = irpsp->Parameters.Write.Length;
复制代码

  1. void IoDetachDevice(
  2.   [in, out] PDEVICE_OBJECT TargetDevice
  3. );  //负责将绑定的设备解除绑定
复制代码
  1. void IoDeleteDevice(
  2.   [in] PDEVICE_OBJECT DeviceObject
  3. );  //删除设备释放内存
复制代码
  1. NTSTATUS KeDelayExecutionThread(
  2.   [in] KPROCESSOR_MODE WaitMode,
  3.   [in] BOOLEAN         Alertable,
  4.   [in] PLARGE_INTEGER  Interval
  5. );  //延时
复制代码
  1. PVOID MmGetSystemAddressForMdlSafe(
  2.   [in] PMDL  Mdl,
  3.   [in] ULONG Priority
  4. );  //返回指定 MDL 描述的缓冲区的非分页系统空间虚拟地址。
复制代码



完整源码:
comcap.c
  1. #include<ntddk.h>
  2. #include<ntstrsafe.h>

  3. #define NTSTRSAFE_LIB  //为了使用静态的ntstrsafe静态库
  4. #define DELAY_ONE_MICROSECOND (-10)
  5. #define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
  6. #define DELAY_ONE_SECOND (DELAY_ONE_MILLISECOND*1000)
  7. #define CCP_MAX_COM_ID 32  //假设最多有32个设备
  8. //保存所有过滤设备指针
  9. static PDEVICE_OBJECT s_fltobj[CCP_MAX_COM_ID] = { 0 };
  10. //保存所有真实设备指针
  11. static PDEVICE_OBJECT s_nextobj[CCP_MAX_COM_ID] = { 0 };

  12. PDEVICE_OBJECT ccpOpenCom();
  13. NTSTATUS ccpAttachDevice();
  14. void ccpAttachAllComs();
  15. void ccpUnload();
  16. NTSTATUS ccpDispatch();
  17. NTSTATUS DriverEntry();

  18. //生成过滤设备并绑定
  19. NTSTATUS ccpAttachDevice(PDRIVER_OBJECT driver, PDEVICE_OBJECT oldobj, PDEVICE_OBJECT* fltobj, PDEVICE_OBJECT* next) {
  20.         NTSTATUS status;
  21.         PDEVICE_OBJECT topdev = NULL;

  22.         //生成设备
  23.         status = IoCreateDevice(
  24.                 driver,//本驱动的驱动对象,由系统给                        
  25.                 0,//设备拓展,此处填0
  26.                 NULL,//设备名称(过滤设备一般不需要名称,故此处填null)
  27.                 oldobj->DeviceType,//设备类型,填被绑定的设备类型即可
  28.                 0,//设备特征,生成设备对象时一般为0
  29.                 FALSE,
  30.                 fltobj);
  31.         if (status != STATUS_SUCCESS) return status;

  32.         //拷贝重要标志位
  33.         if (oldobj->Flags & DO_BUFFERED_IO) (*fltobj)->Flags |= DO_BUFFERED_IO;
  34.         if (oldobj->Flags & DO_DIRECT_IO) (*fltobj)->Flags |= DO_DIRECT_IO;
  35.         if (oldobj->Characteristics & FILE_DEVICE_SECURE_OPEN) (*fltobj)->Characteristics |= FILE_DEVICE_SECURE_OPEN;
  36.         (*fltobj)->Flags |= DO_POWER_PAGABLE;

  37.         //将一个设备保存到另一个设备上
  38.         topdev = IoAttachDeviceToDeviceStack(*fltobj, oldobj);
  39.         if (topdev == NULL) {
  40.                 //如果绑定失败,销毁设备,返回错误
  41.                 IoDeleteDevice(*fltobj);
  42.                 *fltobj = NULL;
  43.                 status = STATUS_UNSUCCESSFUL;
  44.                 return status;
  45.         }
  46.         *next = topdev;

  47.         //设置这个设备已经启用
  48.         (*fltobj)->Flags = (*fltobj)->Flags & ~DO_DEVICE_INITIALIZING;
  49.         return STATUS_SUCCESS;
  50. }


  51. //从名字获取设备对象
  52. PDEVICE_OBJECT ccpOpenCom(ULONG id, NTSTATUS* status) {
  53.         //输入的是串口的id,需要改写成unicode_str的形式
  54.         UNICODE_STRING name_str;
  55.         static WCHAR name[32] = { 0 };
  56.         PFILE_OBJECT fileobj = NULL;
  57.         PDEVICE_OBJECT devobj = NULL;

  58.         //根据id转换成串口的名字
  59.         memset(name, 0, sizeof(WCHAR) * 32);
  60.         RtlStringCchPrintfW(
  61.                 name, 32,
  62.                 L"\\Device\\Serial%d", id
  63.         );
  64.         RtlInitUnicodeString(&name_str, name);

  65.         //打开设备对象
  66.         *status = IoGetDeviceObjectPointer(&name_str, FILE_ALL_ACCESS, &fileobj, &devobj);

  67.         //如果打开成功了,一定要解除引用
  68.         //别忘了这一句:
  69.         if (*status == STATUS_SUCCESS) ObDereferenceObject(fileobj);

  70.         //返回设备对象
  71.         return devobj;
  72. }

  73. //绑定所有的串口
  74. void ccpAttachAllComs(PDRIVER_OBJECT driver) {
  75.         ULONG i;
  76.         PDEVICE_OBJECT com_ob;
  77.         NTSTATUS status;
  78.         for (i = 0; i < CCP_MAX_COM_ID; i++) {
  79.                 com_ob = ccpOpenCom(i, &status);
  80.                 if (com_ob == NULL) {
  81.                         continue;
  82.                 }
  83.                 ccpAttachDevice(driver, com_ob, &s_fltobj[i], &s_nextobj[i]);
  84.         }
  85. }

  86. //分发函数
  87. NTSTATUS ccpDispatch(PDEVICE_OBJECT device,PIRP irp)
  88. {
  89.         PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
  90.         NTSTATUS status;
  91.         ULONG i, j;

  92.         for (i = 0; i < CCP_MAX_COM_ID; i++)
  93.         {
  94.                 if (s_fltobj[i] == device)
  95.                 {
  96.                         //所有电源操作,全部直接放过
  97.                         if (irpsp->MajorFunction == IRP_MJ_POWER)
  98.                         {
  99.                                 //直接发送,然后返回说已经处理了
  100.                                 PoStartNextPowerIrp(irp);
  101.                                 IoSkipCurrentIrpStackLocation(irp);
  102.                                 return PoCallDriver(s_nextobj[i], irp);
  103.                         }

  104.                         //此外我们只过滤写请求,写请求,获得缓冲区及其长度
  105.                         //然后打印
  106.                         if (irpsp->MajorFunction == IRP_MJ_WRITE)
  107.                         {        
  108.                                 //如果是写,先获得长度
  109.                                 ULONG len = irpsp->Parameters.Write.Length;
  110.                                 //然后获得缓冲区
  111.                                 PUCHAR buf = NULL;
  112.                                 if (irp->MdlAddress != NULL) buf = (PUCHAR)MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
  113.                                 else buf = (PUCHAR)irp->UserBuffer;
  114.                                 if (buf == NULL) buf = (PUCHAR)irp->AssociatedIrp.SystemBuffer;

  115.                                 //打印内容
  116.                                 for (j = 0; j < len; ++j)
  117.                                 {
  118.                                         DbgPrint("comcap: Send Data: %2x\r\n", buf[j]);
  119.                                 }
  120.                         }
  121.                         //这些请求直接下发执行即可,我们并不禁止或者改变它
  122.                         IoSkipCurrentIrpStackLocation(irp);
  123.                         return IoCallDriver(s_nextobj[i], irp);
  124.                 }
  125.         }

  126.         //如果根本就不在被绑定的设备中,那就是有问题的,直接返回参数错误
  127.         irp->IoStatus.Information = 0;
  128.         irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  129.         IoCompleteRequest(irp, IO_NO_INCREMENT);
  130.         return STATUS_SUCCESS;
  131. }

  132. //动态卸载
  133. void ccpUnload(PDRIVER_OBJECT drv) {
  134.         ULONG i;
  135.         LARGE_INTEGER interval;

  136.         //首先解除绑定
  137.         for (i = 0; i < CCP_MAX_COM_ID; i++) {
  138.                 if (s_nextobj[i] != NULL) {
  139.                         IoDetachDevice(s_nextobj[i]);
  140.                 }
  141.                
  142.                 //睡眠5秒,等待所有irp处理结束
  143.                 interval.QuadPart = (5 * 1000 * DELAY_ONE_MILLISECOND);
  144.                 KeDelayExecutionThread(KernelMode, FALSE, &interval);

  145.                 //删除这些设备
  146.                 for (i = 0; i < CCP_MAX_COM_ID; i++) {
  147.                         if (s_fltobj[i] != NULL) {
  148.                                 IoDeleteDevice(s_fltobj[i]);
  149.                         }
  150.                 }
  151.         }
  152. }


  153. NTSTATUS DriverEntry(PDRIVER_OBJECT driver,PUNICODE_STRING reg_path) {
  154.         size_t i;
  155.         //所有看的分发函数都设置成一样的
  156.         for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
  157.                 driver->MajorFunction[i] = ccpDispatch;
  158.         }

  159.         //支持动态卸载
  160.         driver->DriverUnload = ccpUnload;
  161.         //绑定所有串口
  162.         ccpAttachAllComs(driver);
  163.         //直接返回成功即可
  164.         return STATUS_SUCCESS;
  165. }
复制代码


sources
  1. TARGETNAME=comcap
  2. TARGETPATH=Release
  3. TARGETTYPE=DRIVER

  4. SOURCES=comcap.c
复制代码

安装后



回复

使用道具 举报

180

主题

231

帖子

1178

积分

金牌会员

Rank: 6Rank: 6

积分
1178
 楼主| 发表于 2022-11-23 01:17:49 | 显示全部楼层
本帖最后由 Grav1ty 于 2022-11-23 12:50 编辑

Linux强制用户下线

w查看用户及其tty
  1. root@VM-16-6-debian:~# w
  2. 00:40:06 up 12 days,  7:54,  3 users,  load average: 0.02, 0.04, 0.00
  3. USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
  4. ****  pts/0    xxx.xxx.xxx.xxx  00:20   12:00  18.77s 17.72s ruby /usr/bin/msfconsole
  5. root     pts/1 xxx.xxx.xxx.xxx 00:29    6:13   0.01s  0.01s -bash
  6. root     pts/2 xxx.xxx.xxx.xxx 00:39    0.00s  0.01s  0.00s w
复制代码
pkill -kill -t tty
  1. pkill -kill -t pts/0
复制代码
效果:


所属该用户的进程也全部结束


注:只有root能让别人下线,且root能让另外一个root下线。



Linux登录管理
who 显示当前当登录的用户的信息
w 显示登录的用户及其当前执行的任务
users 显示当前当登录的用户的用户名
last 显示当前与过去登录系统的用户的信息
lastb 显示所有登录系统失败的用户的信息 不看不知道 我的ssh正在被别人爆破。。。

lastlog 显示用户最后一次登录的信息




windows自带工具certutil

总是用certutil -hashfile看文件的哈希值,却一直没好好学一下这东西还有其他什么用


Certutil是一个CLI程序,可用于转储和显示证书颁发机构(CA),配置信息,证书服务,CA组件的备份和还原以及验证证书,密钥对和证书链,它作为证书服务的一部分安装。
这个工具从windows2003开始就系统自带


以下举例一些基础的,常用的 还有高级的可查看文档 附在末尾了
base64编码:
  1. certutil -encode 目标文件 生成文件
复制代码
16进制编码:
  1. certutil -encodehex 目标文件 生成文件
复制代码


解码base64
  1. certutil -decode new.txt target.txt
复制代码
解码16进制
  1. D:\>certutil -decodehex new1.txt target1.txt
复制代码




散列:
命令就不敲了,直接看图


所以这东西在免杀上有奇效

另外他还可以下载文件 类似curl -o 有些文章说可以配合编码达到落地免杀效果 我没试过
  1. certutil -urlcache -split -f 目标地址
复制代码




它还可以查看错误码
  1. certutil -error 错误码
复制代码



更全的可以看这篇 几乎可以当字典查:
  1. https://blog.geekdt.com/636.html
  2. https://zhuanlan.zhihu.com/p/107415501
复制代码
还有ms的官方文档:
  1. https://learn.microsoft.com/zh-cn/windows-server/administration/windows-commands/certutil?view=vs-2015
复制代码






回复

使用道具 举报

180

主题

231

帖子

1178

积分

金牌会员

Rank: 6Rank: 6

积分
1178
 楼主| 发表于 2023-2-5 21:53:20 | 显示全部楼层
本帖最后由 Grav1ty 于 2023-2-15 17:51 编辑

linux shell 笔记

最近在看shell cookbook,对着书上敲了一下命令,还挺有意思的,遂记录一下,当作笔记,希望能坚持下来
shebang:指#!/bin/bash 本书均在bash环境下实验
echo:双引号解析特殊字符,如"!;"等,单引号不作任何解析,结尾自动添加换行符
          -n 禁止结尾自动添加换行符

          -e 解析反斜杠转义,echo默认不解析反斜杠转义
              打印彩色文本:\e[1;31m 其中31可换成其他颜色码描述,\e[0m将颜色重置

              打印彩色背景:\e[1;42m 可以观察到只有31->42的区别,这其实就是颜色码的问题,据说颜色码保存在/etc/DIR_COLORS但是我的设备找不到这个文件不知道什么原因。


                另外在过程中发现一个有趣的问题:怎样把Linux命令行带颜色的输出保存到文件?给出的答案是欺骗isatty(),这个留到后面考究

printf:接受引用文本或由空格分隔的参数,可用格式化字符串形式,和c语言标准库中printf差不多。结尾不会自动添加换行符
pgrep:查看某进程PID
           -u 查看属于指定用户的进程PID
cat /proc/$PID/environ:查看某进程环境变量
                                   此特殊文件是一个包含环境变量以及对应变量值的列表,用NULL字符\0分割,可以用cat /proc/$PID/environ | tr '\0' '\n'读取

赋值:var=value将value赋值给var变量,在变量名之前用$可以访问变量内容
                           但注意一个常见错误,=号两边不能有空格,即不能写作var = value,这表示等量关系测试
export:声明将由子进程所继承的一个或多个变量
$PATH:列出一系列供shell搜索特定应用程序的目录,一般定义在/etc/environment,/etc/profile或~/.bashrc中
${#var}:获取变量var的长度

$SHELL:获取当前shell种类,echo $SHELL和echo $0输出一致


2月8日更新

prepend() { [ -d "$2" ] && eval $1=\"$2':'\$$1\" && export $1; }  在.bashrc中添加该句,定义prepend函数,添加变量

首先确认第二个参数指定目录是否存在,之后eval表达式将第一个参数所指定的变量值设置成第二个参数值 + :随后再跟上第一个参数的原始值。

当然这会产生一个问题,如果变量为空,则会在末尾留下一个:,解决问题的方法很多,书上引入了shell参数扩展的形式 ${parameter:+expression}如果parameter有值且不为空,则使用expression的值

修改后的样子:

prepend() { [ -d "$2" ] && eval $1=\"$2\$\{$1:+':'\$$1\}\" && export $1; }


let:直接执行基本的算数操作,变量名之前不需要加$,且能实现自加,自减



[]:这其实是一个操作符 使用方式和let一样,但[]前一定要加$

                                  外面加了$表示[]用于运算,此时内部如果有变量可以不加$(加了也没事)

                                  如果外面不加$,则此时[]不做运算,只是简单的赋值操作





(()):和[]用法一致,注意情况也一致,在外部要加上$,内部无所谓



expr:同样用于基本算数操作,但要注意数字和运算符之间要留空格,这类似于一个命令。     我理解为上述[],(())都是运算符的一种,而let,expr都是一种命令



以上不支持浮点数运算,bc是用于数学计算的高级工具,可以执行浮点运算,我-h看了一下还能用-i进入交互模式

bc还能设置小数精度,如scale=2设置小数点后2位

                  进制转换,如obase=2转2进制

                  计算平方根,平方等



>:覆盖写入

>>:追加写入

echo $?:打印上一条指令的退出状态,0为成功,非0为失败(我很好奇这非0的值是什么,我十分怀疑是errno的值)




2月9日更新
重定向
           0--stdin标准输入
           1--stdout标准输出
           2--stderr标准错误
将stderr重定向到stdout,全部输出到目标中
                         >targetFile 2>&1
                         &>


stdout作为单数据流,可以被重定向到文件或是通过管道传入其他程序,但是二者无法兼得
tee命令为此提供了解决方法,tee命令从stdin中读取,然后将输入数据重定向到stdout以及一个或多个文件中
                 command | tee FILE1 FILE2 | other command
cat -n:从stdin中接收每一行数据前加上行号并写入stdout
注意:tee只能从stdin中读取数据,并不能从stderr中读取数据
           默认情况下,tee将文件覆盖,但提供-a选项,用于追加内容


/dev/stdin
/dev/stdout
/dev/stderr对应表示文件描述符0,1,2

重定向脚本内部的文本块
将脚本中的文本重定向到文件,如下将一条警告信息添加到自动生成的文件顶部


我的理解,这个操作将cat后的EOF看做是一个flag(当然可以不是EOF,可以是任意标记如XXX),然后往后直到单独的flag行(注意一定要是单独的行,行中出现flag字符不算),将其间文本输入到>后的文件中



2月10日更新
自定义文件描述符
exec创建全新的文件描述符
               <:只读模式
               >>:追加写入模式
               >:截断写入模式

我试了试,这个还是挺好用的,但要注意以下几点:
       1.只读,追加写入,截断写入(就是覆盖),这几种都是针对exec这个命令而言的,就是假如说exec 3>input.txt,那么input.txt会先被清空,然后但是之后每次执行>&3的时候都是在input.txt后面追加内容,而不是再执行覆盖写入;同理如果执行exec 3>>input.txt,那么就是直接在input.txt原有内容再往后追加写入。
       2.每次执行是可以覆盖的,比如exec 3>input.txt之后,再执行exec 3>inputFake.txt,那么描述符3是指向inputFake.txt而不是input.txt
       3.指向的文件必须已经存在,exec不会帮你创建


数组与关联数组
       简而言之,数组就是普通以int型为下标的数组,而关联数组有点像键值对,是以字符串为下标
       另外,bash version>=4.0才支持关联数组

数组
       查找数组必须用${数组名[下标]},如果只用$数组名,则输出[0]对应的值,就像c中的数组一样


${数组名}   或   ${数组名[@]}:打印数组中的所有值
${#数组名}:打印数组长度(如果*换成数字的话就是打印对应值的长度,越界输出0)
  1. 这个编辑框是有什么bug么,[*]会解析成换行+一个·
复制代码



关联数组
       使用前必须先用declare -A定义
       格式为“索引--值”,赋值的时候索引用[]裹起来如ass_array[index1]=value1
       关联数组名前面加!可以输出对应的索引值,如!ass_array输出所有索引值(此方法对数组同样适用)
       注意,如果先定义了ass_array并赋值之后,再重新定义ass_array并不会清空ass_array

这里有一个很有意思的事,我先定义的index2,再定义index3,但是输出索引值的时候先输出index3,很奇怪


alias:别名 unalias取消别名

小技巧:命令前加\可以忽略别名,直接执行命令。这样可以避免黑客恶意设置别名


采集终端信息
tput
      tput cols:获取终端行数
      tput lines:获取终端列数
      tput longname:获取终端名
      tput cup 100 100:将光标移动到(100,100)处
      tput setb n:设置终端背景色(n=0-7)
      tput setf n:设置终端前景色(n=0-7)(某些命令,如color,ls等在内的一些命令可能会重置前景色和背景色,这取决于这些命令的实现逻辑)


stty
      -echo:禁止将输出发送到终端
      echo:允许发送到终端


执行结果



2月11日更新
date:获取当前时间
        +%s:打印纪元时,带有前缀+的格式化字符串作为date的参数,将打印出对应格式的日期
        --date:指定作为输入的时间,如date --date "Wed mar 15 08:09:16 EDT 2017" +%s将Wed mar 15 08:09:16 EDT 2017转化为纪元时
        -s:设置时间,字符串需为格式化的字符串,也可以用/usr/sbin/ntpdate来设置网络时间
如果需要对命令计时,更好的选择是time,date的最小精度是秒

date所支持的格式选项
工作日%a 如Sat
%A如Saturday
%b如Nov
%B如November
%d
制定格式日期(mm/dd/yy)%D
%y如10
%Y如2010
小时%T或%H
分钟%M
%S
纳秒%N
Unix纪元时%s

tput补充
      tput sc:记录当前光标位置
      tput rc:将光标恢复到sc保存的位置
      tput ed:清空光标后的内容(当用类似tput rc等跳转光标的指令时,可能跳转到显示文本的位置,此时可以用tput ed清空显示文本)

seq a b:生成a到b的一系列数字
{start...end}:迭代从start到end的值,这是一个“语言构件(construct)”,执行速度要比seq略快

shell调试:
        执行时用-x选项,如bash -x test.sh
        在shabang处将#!/bin/bash 改为#!/bin/bash -xv
        在shell内用set声明
                   set -x:在执行命令时显示参数和命令
                   set +x:禁止调试
                   set -v:当命令进行读取时显示输入
                   set +v:禁止打印输入

定义函数
       直接定义fname(){ statement;}                  #(注意一行写完时要带分号)
       用function fname(){
                        statement;
}定义

调用函数时只需要使用函数名即可,如果有参数,则用fname arg1 arg2这种格式调用

参数可以按位置访问,以下是一些tips
       $0:脚本名称
       $1:第一个参数
       $2:第二个参数
       $n:第n个参数
       "$@":扩展成"$1" "$2" "$3"等
       "$*":扩展成“$1c$2c$3c”,其中c是IFS的第一个字母
       "$@"比"$*"用的多,由于"$*"将所有参数当做一个字符串输出,因此很少被使用

这里出现了一个有意思的IFS(Internal Field Seprator)
直接输出IFS是看不到值的,转化为二进制就能够看到了,"040"是空格,"011"是Tab,"012"是换行符"\n" 。最后一个 012 是由于 echo 默认是会换行的。
实际应用:
#!/bin/bash
OLD_IFS=$IFS #保存原始值
IFS="" #改变IFS的值
...
...
IFS=$OLD_IFS #还原IFS的原始值





2月15日更新

递归
在bash中同样能让函数递归执行
F() { echo $1; F hello; sleep 1; }
  1. :(){ :|:& };:   #详见en.wikipedia.org/wiki/Fork_bomb这个命令会不对衍生出进程 因而被称为Fork炸弹
复制代码
可以通过配置/etc/security/limits.conf中的nproc来限制可生成的最大进程数来阻止这种攻击
hard nproc 100  #将所有用户可生成的最大进程数限制为100

导出函数
函数也能像export一样导出,让子进程继承
export -f fname
不知为何我在某台debian下并不能实现 但在本机可以实现


利用子shell生成一个独立的进程,可以用()来定义一个子shell
很有趣的是本机的bash用ls也有彩色效果 但是上面用另外一台机子不行


引用子shell保留空格和换行符
假设用子shell或反引号的方法将命令的输出保存到变量中,为了保留输出的空格和换行(\n),必须要用双引号
我没有成功复现 就不截图了

有时候读输入,不能方便的通过按回车键判断输入结束,此时要用read。一般输入完毕通过输入到某个特定字符来决定,或者通过输入的字符数来决定
read
       -n:读入n个字符结束
       -d:用特定的定界符作为输入行的结束
       -s:无回显的方式读入(之前通过stty -echo的方法实现)
       -p:显示提示信息
       -t:在给定的时间内读取输入(单位:秒)

持续运行命令直到执行成功

给定一个函数
repeat()
{
  while true
  do
    $@ && return
  done
}
执行命令成功退出,否则一直执行

一种更快的做法:大多数现代系统中,true是作为/bin中的一个二进制文件来实现的,这意味着每次while的时候shell都要派生一个进程。为了避免这种情况,可以用shell的内建命令:,该命令的退出状态总是为0。


改进的方式:
repeat() { while :; do $@ && return; done }
加入延时:
如果用repeat配合wget从网络上下载东西,如果不成功就一直执行,那么很有可能被识别为dos攻击
那么加入sleep即可,延时单位为秒
repeat() { while :; do $@ && return; sleep 30; done }


回复

使用道具 举报

180

主题

231

帖子

1178

积分

金牌会员

Rank: 6Rank: 6

积分
1178
 楼主| 发表于 2023-2-8 16:05:57 | 显示全部楼层
本帖最后由 Grav1ty 于 2023-2-8 16:07 编辑

IO多路复用

select 时间复杂度O(n)
  1. 原理:
  2.     1.它仅仅知道 有I/O事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流对他们进行操作。
  3.     所以select具有O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长。
  4.     2.select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。

  5. 缺点:
  6.     1.每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大。需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大
  7.     2.对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低:
  8.        当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,那就避免了轮询,这正是epoll与kqueue做的。
  9.     3.select支持的文件描述符数量太小了,默认是1024
  10.         单个进程可监视的fd数量被限制,即能监听端口的大小有限。
  11.         一般来说这个数目和系统内存关系很大,具体数目可以cat /proc/sys/fs/file-max察看。32位机默认是1024个。64位机默认是2048.
复制代码


poll 时间复杂度O(n)
  1. 原理:
  2.     1. poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,
  3.     如果设备就绪则在设备等待队列中加入一项并继续遍历,
  4.     如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。
  5.     2. 但是它没有最大连接数的限制,原因是它是基于链表来存储的.

  6. 缺点:  
  7.     1、大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。                  
  8.     2、poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。
复制代码


epoll 时间复杂度O(1)
  1. 原理:
  2.     epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。
  3.     所以我们说epoll实际上是事件驱动(每个事件关联上fd)的,此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1))
  4.     epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。

  5. epoll有EPOLLLT和EPOLLET两种触发模式
  6.     LT模式(默认的模式)
  7.         只要这个fd还有数据可读,每次 epoll_wait都会返回它的事件,提醒用户程序去操作,
  8.     ET模式(边缘触发) “高速”模式
  9.         它只会提示一次,直到下次再有数据流入之前都不会再提示了,无 论fd中是否还有数据可读。
  10.         所以在ET模式下,read一个fd的时候一定要把它的buffer读光,也就是说一直读到read的返回值小于请求值,或者 遇到EAGAIN错误。
  11. epoll的优点:
  12.     1、没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口);
  13.     2、效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;
  14.     即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。
  15.     3、 内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销。
复制代码


select、poll、epoll 区别
  1. select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。  
  2. epoll跟select都能提供多路I/O复用的解决方案。在现在的Linux内核里有都能够支持,其中epoll是Linux所特有,而select则应该是POSIX所规定,一般操作系统均有实现

  3. 1、支持一个进程所能打开的最大连接数
  4.     select
  5.         单个进程所能打开的最大连接数有FD_SETSIZE宏定义,其大小是32个整数的大小(在32位的机器上,大小就是3232,同理64位机器上FD_SETSIZE为3264),当然我们可以对进行修改,然后重新编译内核,但是性能可能会受到影响,这需要进一步的测试。
  6.     poll
  7.          poll本质上和select没有区别,但是它没有最大连接数的限制,原因是它是基于链表来存储的
  8.     epoll
  9.         虽然连接数有上限,但是很大,1G内存的机器上可以打开10万左右的连接,2G内存的机器可以打开20万左右的连接
  10. 2、FD剧增后带来的IO效率问题
  11.     select
  12.         因为每次调用时都会对连接进行线性遍历,所以随着FD的增加会造成遍历速度慢的“线性下降性能问题”。
  13.     poll
  14.         同上
  15.     epoll
  16.         因为epoll内核中实现是根据每个fd上的callback函数来实现的,只有活跃的socket才会主动调用callback,所以在活跃socket较少的情况下,使用epoll没有前面两者的线性下降的性能问题,但是所有socket都很活跃的情况下,可能会有性能问题。
  17. 3、 消息传递方式
  18.     select
  19.         内核需要将消息传递到用户空间,都需要内核拷贝动作
  20.     poll
  21.         同上
  22.     epoll
  23.         epoll通过内核和用户空间共享一块内存来实现的。
  24. 总结:
  25.     1、表面上看epoll的性能最好,但是在连接数少并且连接都十分活跃的情况下,select和poll的性能可能比epoll好,毕竟epoll的通知机制需要很多函数回调。
  26.     2、select低效是因为每次它都需要轮询。但低效也是相对的,视情况而定,也可通过良好的设计改善
  27.     3、select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。
  28.     4、select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销。
复制代码
  1.         select  poll    epoll
  2. 操作方式    遍历  遍历  回调
  3. 底层实现    数组  链表  红黑树
  4. 最大连接数   1024(x86)或2048(x64) 无上限 无上限
  5. IO效率   
  6.     每次调用都进行线性遍历,时间复杂度为O(n)  
  7.     每次调用都进行线性遍历,时间复杂度为O(n)  事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到readyList里面,时间复杂度O(1)
  8. fd拷贝   
  9.     每次调用select,都需要把fd集合从用户态拷贝到内核态   每次调用poll,都需要把fd集合从用户态拷贝到内核态 调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝
复制代码
源码参考https://github.com/caijinlin/lea ... ree/master/linux/io
作者似乎用的是Unix网络编程的例子,其实我还是没有十分理解用这种事件驱动并发的优点...
回复

使用道具 举报

180

主题

231

帖子

1178

积分

金牌会员

Rank: 6Rank: 6

积分
1178
 楼主| 发表于 2023-6-3 21:09:39 | 显示全部楼层
本帖最后由 Grav1ty 于 2023-6-3 21:29 编辑

man手册分成很多section,使用man时可以指定不同的section来浏览,各个section意义如下:

1 - commands
2 - system calls
3 - library calls
4 - special files
5 - file formats and convertions
6 - games for linux
7 - macro packages and conventions
8 - system management commands
9 - 其他
解释一下:
1是普通的命令

2是系统调用,如open,write之类的(通过这个,至少可以很方便的查到调用这个 函数,需要加什么头文件)

3是库函数,如printf,fread

4是特殊文件,也就是/dev下的各种设备文件

5是指文件的格 式,比如passwd, 就会说明这个文件中各个字段的含义

6是给游戏留的,由各个游戏自己定义

7是附件还有一些变量,比如向 environ这种全局变量在这里就有说明

8是系统管理用的命令,这些命令只能由root使用,如ifconfig


man中文计划:man-pages-zh_cn
切换完man-pages后要执行mandb更新man目录

权限不够记得sudo

很奇怪archlinux下用pacman安装bcc-tools之后找不到 man perf和man opensnoop。。。

但是debian下用apt install bpfcc-tools之后man perf和opensnoop是有结果的
回复

使用道具 举报

180

主题

231

帖子

1178

积分

金牌会员

Rank: 6Rank: 6

积分
1178
 楼主| 发表于 2023-6-14 20:10:41 | 显示全部楼层
Grav1ty 发表于 2022-5-1 14:51
备忘

文件权限-rwxrwxrwx,转化数字777的意思

https://www.pathname.com/fhs/pub/fhs-2.3.html
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-4-20 09:41 , Processed in 0.025296 second(s), 17 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表