首页
Search
1
[CTF/Reverse] 2022DASCTF X SU 三月 逆向部分
135 阅读
2
[CTF/Reverse] [HWS2022硬件安全 x DAS Jan] EasyVM + BabyVM
125 阅读
3
[CTF/Reverse] [XMAN2018排位赛]easyvm
92 阅读
4
[CTF/Reverse] [GWCTF 2019]babyvm
88 阅读
5
[应用/笔记]Typecho博客搭建
76 阅读
原创
笔记
程序员的自我修养
CTF
Reverse
Pwn
登录
Search
Yirannn
累计撰写
65
篇文章
累计收到
3
条评论
首页
栏目
原创
笔记
程序员的自我修养
CTF
Reverse
Pwn
页面
搜索到
14
篇与
的结果
2021-09-08
[学习/笔记] 程序员的自我修养-第二章
编译和链接2.1 编译 编译可以分为四个步骤:预处理(Prepressing),编译(Compilation),汇编(Assembly),链接(Linking)2.1.1 预编译(cc1)(以gcc为例) 预编译负责展开#开始的预编译指令,如include、define、ifdef等,对于define直接展开,对于include递归引用。删除注释、添加行号,保留#pragma2.1.2 编译 (cc1) 经过词法分析、语法分析、语义分析、优化后产生汇编代码文件2.1.3 汇编(as) 将汇编代码转换成机器码,只是根据汇编和指令的对照一一翻译即可2.1.4 链接(ld) 将目标文件链接到一起,得到可执行文件2.2 编译器做了什么 书上以 array[index] = (index + 4) * (2 + 6) 举例2.2.1 词法分析 源代码被输入到扫描器,扫描器负责词法分析,将字符串分割成一系列的记号(Token)如 array、[、index、]等共16个记号将会被分类,array、index等标识符将会被送到符号表,4、2、6等常量将会被送到文字表2.2.2 语法分析 语法分析器对扫描器产生的符号进行语法分析、产生语法树,以表达式为节点,例子的语法树如下: 此时也将确定一些符号的优先级和含义,同时如果发现不合法也会在此阶段报告语法分析的错误2.2.3 语义分析 语义分析由语义分析器完成,语法分析无法判断一个表达式是否真正的有意义,比如两个指针的乘法运算尽管是在语法上合法的,但是显然是没有意义的。动态语义只有运行期间确定,而语义分析负责分析静态语义,语义分析会在语法树上标识类型,隐式转换也是在这个期间完成的2.2.4 中间语言生成 在这里,源码级优化器将会进行一次优化,如(2+6)这个在编译阶段就可以获得固定值的表达式将会直接优化成8,具体的优化过程日后编译原理再学,现在只做简单了解。 编译器可以被分为前端和后端。前端负责产生中间代码,中间代码是和运行硬件无关的,后端将中间代码转化成机器码。我认为LLVM就是一个比较典型和广泛的前后端分离编译器。用同一个优化前端生成IR码,再通过不同的后端翻译成不同平台的机器码。2.2.5 目标代码的生成和优化 这个阶段,编译器后端(主要由代码生成器和目标代码优化器组成)将会把中间代码转换成目标机器码。这部分的优化类似选择合适的寻址方式、利用位移代替乘法、删除多余指令等 经过了以上的步骤,源代码已经被编译成了目标代码,但是这时候index和array的地址还没有确定,由此我们可以引入链接的问题:若index和array的地址在其他编译单元中,就需要链接器出马把它们翻译成相应的地址2.3 链接 由于软件的规模日益增长,庞大的代码量使得人们为了修改和复用构建了模块化的组织形式,不同的模块需要按照层次结构或者约定的其他结构组织。如何将模块复合到一起,实现模块间的函数调用以及模块间的变量访问(这两个问题可以归结为一个问题:如何跨模块引用符号(Symbol)(符号往往代表着一个地址,可能是函数也可能是变量的起始地址))书上用了一个形象化的方式解释:定义符号的模块相当于多出一块区域的拼图版,而引用对应符号的模块相当于刚好少这样一块区域的拼图版。这样的拼接过程也就是链接(Linking)2.4 静态链接 链接主要包括了地址空间分配、符号决议和重定位的步骤。每个模块的源代码经过编译器生成目标文件,目标文件和库一起链接成可执行文件。当我们在main.c中引用func.c中的函数foo(),main的每一处foo调用都必须要知道foo的地址,在编译时,编译器并不知道foo的地址,所以暂时不处理这样的地址。在链接时,链接器会自动的去相应的func中找到foo的地址并填会main。这个过程也称为重定位,使得对绝对地址引用的位置指向正确的地址
2021年09月08日
29 阅读
0 评论
0 点赞
2021-09-07
[学习/笔记] 程序员的自我修养-第一章
回顾1.1 本书在1.1阐述了未来整本书中将要带领读者走入的问题,在这里暂时记录一下,希望未来回头看的时候能有些更加深刻/更加正确的答案1. 程序为什么要被编译器编译了之后才可以运行? 因为处理器并不能处理高级语言代码,需要经过编译器编译、链接之后,转化成机器可以识别的机器码,再由系统解析将命令送到CPU处理2. 编译器在把C语言程序转换成可以执行的机器码的过程中做了什么,怎么做的? 编译器通过语法树等的处理,首先处理预编译命令,然后将代码翻译成对应的汇编代码,将汇编代码处理格式后形成汇编目标文件,最后将目标文件链接为可执行文件。3. 最后编译出来的可执行文件里面是什么?除了机器码还有什么?它们怎么存放的,怎么组织的? 要想谈可执行文件是如何组织的,必须要先限定可执行文件的格式,我想以Win PE文件举例。主要内容由PE文件头、块表和块组成,块内存放如数据、代码等4. #include<stdio.h> 是什么意思?把 stdio.h 包含进来意味着什么?C 语言库又是什么?它怎么实现的? 这是一句预编译命令,实际上在编译器编译过程中,会直接将 stdio.h 展开到代码中。包含意味着引用整个 libc 中 stdio 部分的内容。C 语言库是一个在统一标准下实现的一些接口和函数,它们封装了一些与系统交互的调用或者应用性函数,常见的一例实现是 glibc5. 不同的编译器 (Microsoft VC/GCC) 和不同的硬件平台 (x86/SPRAC/MIPS/ARM) ,以及不同的操作系统 (Windows/Linux/UNIX/Solaris), 最终编译出来的结果一样么?为什么? VC 和 GCC 都是 C 标准的一种实现,它们的语义分析、构造习惯、库函数以及底层实现与优化都有可能不同,自然编译出的结果都不一样。至于不同的硬件平台,不管是汇编结果还是实际的机器操作码都不一样,自然编译结果一定不同。对于不同的操作系统,所要求的可执行文件格式和结构、代码组织方式都不同,如 PE 与 ELF。与系统对应的接口也不尽相同,自然编译结果不同。6. Hello World 程序是怎么运行起来的?操作系统是怎么装载它的?它从哪儿开始执行,到哪儿结束?main 函数之前发生了什么? main 函数结束以后又发生了什么? 不甚了解,仍需学习7. 如果没有操作系统,Hello World 可以运行吗? 如果要在一台没有操作系统的机器上运行 Hello World 需要什么? 应该怎么实现? 可以,操作系统封装了资源调配和硬件接口,单程序运行时无需考虑资源调配,但需要正确的将操作传递到对应硬件的控制器中8. printf 是怎么实现的?它为什么可以有不定数量的参数?为什么它能在终端上输出字符串? printf通过解析参数,将不同类型的数据转换为字符串,通过libc的一系列调用最后调用linux系统调用write,write会负责在终端上输出字符串。不定数量参数是在printf定义时引入va_list的结果。9. Hello World 程序在运行时,它在内存中是什么样子的? 有代码段、数据段、堆栈空间等排列构成,尽管IDA中看过多次内存分布,但是目前对此问题还是不甚了解。 1.2 硬件结构1.2.1 框架 本节主要讲述了基本的硬件结构框架, 南桥所连接的设备暂时不是我需要深究的结构。尽管计算机硬件系统越来越复杂,但是在从程序的角度了解计算机时,我们可以简单的将它看成最初的模型1.2.2 SMP与多核 我认为在初步了解过程当中,简单的将多核认为成多个并行的、共享缓存的处理器即可。必须要注意的是双核并不能将一件计算任务的效率提升一倍,就像一个女人可以十个月生出一个孩子,但是两个女人并不能在五个月生出一个孩子一样。1.3 系统结构 我们在了解系统结构的过程中,可以将体系结构层次化。称层与层之间的通信协议为接口。相同的接口和这种层次化的设计模式带来的一项极大优点:兼容性。层次结构可以在尽可能少改变其他层的情况下,增加一个层就可以提供前所未有的功能。 应用层使用操作系统应用程序编程接口 (Application Programming Interface) 。API由运行库提供,比如 Glibc 提供 POSIX 的 API,Win 运行库提供 Windows API。运行库使用操作系统提供的系统调用接口 (System call Interface). 系统调用一般使用软件中断的方式提供。如 Linux 的 0x80,Windows 的 0x2E。硬件是硬件接口的定义与提供者,操作系统内核及其运行的驱动程序是硬件接口的使用者。我们常称硬件接口为硬件规格(Hardware Specification )我们可以用一张图来简单的描述计算机软件体系结构。1.4 操作系统 操作系统一方面要提供抽象的接口,另一方面需要管理硬件资源。1.4.1 CPU 在发展早期,CPU同时只能运行一个程序,在这种情况下,当进行IO操作时,CPU将进入空闲状态。控制CPU资源的第一步是多道程序(Multiprogramming),它做的只是简单的在某个程序无需使用CPU时,将另外正在等待CPU的资源启动。这样带来的最大问题是程序之间没有权重,急需运行的程序无法得到及时运行。 然后,CPU的调度方式变成了协作模式,每个程序运行一点时间后,主动让出CPU资源给其他程序,我们称这种模式为分时系统(Time-Sharing System),这种系统的出现使得交互式操作可以被立即看到效果,Windows早期版本和mac OS都是采用这种方式来调度程序的。这样的弊端是一旦某个程序陷入死循环,都会导致系统死机。 多任务(Multi-Tasking)系统则解决了这种弊端,系统接管了所有的硬件资源,并且运行在一个受保护的级别,而程序以进程(Process)的方式运行在更低权限的级别,CPU资源由操作系统统一分配。如果某个程序运行超过一定时间,系统会剥夺CPU资源并分配给其他进程,几乎所有现代操作系统都使用这种方式。1.4.2 硬件驱动工作 应用程序需要看到的是一个统一的硬件访问模式。在操作系统成熟之前,程序员确实需要和不同的硬件接口打交道,不同型号的设备访问方式都不尽相同。操作系统使得硬件在面向应用时抽象成了一系列概念。Windows中,图形硬件被抽象成GDI,声音与多媒体设备则被抽象成DirectX,UNIX中则被抽象成普通的文件。与不同硬件的交互则交由驱动程序来完成。驱动与操作系统内核一起运行在特权级,但是有与内核间有一定的独立性。操作系统为硬件厂商提供了一系列接口和框架,按照其开发的驱动程序都能在操作系统上使用。 本书中以文件读取操作举例了操作系统和驱动程序的工作过程: 当在Linux系统中,要读取某个文件的前4096字节时,程序会向系统发出read系统调用。在文件系统收到请求之后,判断出文件前4096字节位于1000到1007号扇区。这之后文件系统就向硬盘驱动发出一个读取自1000号逻辑扇区开始的8个扇区的请求,驱动程序收到请求后向硬盘发出硬件命令。通常通过读写IO端口寄存器实现,x86平台共有65536个硬件端口寄存器,CPU提供了 IN 和 OUT 指令来实现对硬件端口的读写。 对于IDE( 电子集成驱动器, 把硬盘盘体与硬盘控制器集成在一起 )接口来说,它有两个通道,每个通道有两个设备。正常情况下我们的文件位于 IDE0 的 Master磁盘上。IDE0的IO端口地址是0x1F0~0x1F7以及0x376~0x377,通过读写这些地址就可以与IDE进行通信,以实现读取1000号逻辑扇区开始的8个扇区为例: 第0x1F3~0x1F6 4个字节的端口是用来写入LBA地址( 逻辑区块地址,描述扇区编号位置 )的,所以我们要把1000写在这里,也就是0x000003E8,将0x00写入0x1F3、0x1F4,将0x03写入0x1F5,将0xE8写入0x1F6 0x1F2写入需要读写的扇区数,我们写入8. 0x1F7写入执行操作的OP code,对于读取来说,OP Code为 0x20out 0x1F3, 0x00 out 0x1F4, 0x00 out 0x1F5, 0x03 out 0x1F6, 0xE8 out 0x1F2, 0x08 out 0x1F7, 0x20 收到这个命令后,硬盘就会执行相应的操作,将数据读取到预设的内存中。实际上,驱动程序还需要考虑硬件状态和调度效率,来达到最高的性能。1.5 内存 讨论过CPU和IO调度后,来到第三个最重要的硬件:内存 在早期的计算机上,程序直接运行在物理内存上。随着计算机发展,这样的直接的方式已经不足以满足人们的效率需要。我们需要解决这样的内存分配问题。 • 地址空间隔离:防止不完善的程序修改其他程序的内存数据、防止恶意程序恶意破坏其他程序的内存数据 • 内存使用效率:由于内存是有限的,为了保证前台进程在内存中执行,后台程序的内存可能会被释放到硬盘中。如果调配方案不优,会导致大量的数据在IO,浪费时间,效率低下。 • 程序运行地址:程序内存地址需要确定,因为程序编写时访问、跳转的内存地址都是固定的,其中重定位问题会在2、3章详细讨论。 为了解决这样的问题,我们增加了一个中间层:把程序地址看作虚拟地址,然后映射到实际地址上,只要能控制映射过程,就可以保证程序之间访问的物理内存不重叠/1.5.1 隔离 对于32位机来讲,能使用的实际地址是 MAX(2^32, Actual Memory), 物理地址空间是实际存在的,而虚拟空间是不存在的,每个进程都有自己独立的虚拟空间,并且只能访问自己的地址空间,这样就可以实现进程隔离1.5.2 分段 早期采用分段的方式进行内存映射,举例:A需要10 MB内存,我们假设一个0x0到0xA00000大小的虚拟空间,然后从实际内存中分配一段大小相同的物理地址,如0x100000到0xB00000,将这两块空间一一映射,映射通过操作系统设置,通过硬件完成地址转换,可以举一列内存映射如图所示 分段的方法解决了隔离和运行地址的问题,程序之间内存不重叠,无需重定位。但是仍然没有解决内存使用效率的问题。事实上,根据程序的局部性原理(一段时间内,程序仅限执行某一部分,访问空间仅限于某个内存区域),我们需要一个更小粒度的内存分割和映射的方法,提高内存的使用率:分页(Paging)1.5.3 分页 将地址空间划分为等大小固定大小的页,把常用的数据和代码页装载到内存中,把不常用的保存在磁盘里,需要的时候再取出来即可。举例:我们有两个进程Process1和Process2,他们中的部分虚拟页面被映射到了物理页面,VP0、VP1和VP7映射到PP0、PP2和PP3,VP2和VP3则位于磁盘的DP0和DP1中,VP是处于虚拟空间的虚拟页,PP是内存中的物理页,DP是磁盘中的磁盘页,虚拟空间中的一些页面会被映射到同一个物理页,实现内存共享 当Process1需要用到VP2和VP3两个内存页面时,硬件会捕获到Page Fault,然后操作系统接管进程,负责把VP2和VP3装入内存然后建立映射。同时,操作系统可以对页面设置权限,通过这样的方式保护自己和保护进程。 一般来讲,CPU发出一个虚拟地址,通过MMU处理之后转换为物理地址,再将物理地址传送给内存1.6 线程1.6.1 线程基础- 线程,也会被称为轻量级进程。随着CPU向多核方向发展,多线程作为并发执行的重要方法也越来越重要。 - 一个进程由一个到多个线程组成,它们共享内存空间(代码段、数据段、堆等) - 对长时间等待的操作,多线程可以合理利用等待时间提高任务执行效率 - 对计算密集的操作,可以一个线程负责交互一个线程负责计算,避免计算阻塞交互 - 有的程序本身需要并发,使用多线程并发,对于多核CPU,并发能更好的利用CPU资源。 - 相比多进程,多线程的数据共享效率更高 关于线程权限 一般来讲,栈空间,TLS数据(操作系统为线程提供的私有空间),局部变量时线程所私有的数据,全局变量,堆数据、静态变量、代码空间和打开的文件是线程的公有数据。若核心数大于线程数,线程的并发是真正的并发,否则操作系统会让多线程程序轮流执行,快速在运行、就绪、等待中切换,可执行时间被称为时间片,时间片耗尽或者线程主动释放,将会进入ready或者wait。其中前者被剥夺资源的过程称为抢占 更高优先级的线程会更早的执行,系统可能自动调整优先级,IO密集型线程将会比CPU密集型线程更容易得到优先级提升。用户也可以指定优先级。 抢占式执行会导致线程调度时机不确定,产生一些竞争问题。 Windows采用CreateProcess和CreateThread来产生进程和线程,并有API针对性操控,但是Linux对线程控制的方法较为贫乏: fork() 复制当前进程 exec() 使用新的可执行映像覆盖当前可执行映像 clone() 创建子进程并从指定位置执行。 fork不复制内存空间,采用写时复制的方式,也就是当某个Task对内存修改的时候,再复制一份提供给修改方使用 fork配合exec才可以启动别的新任务。产生新线程一般使用clone1.6.2 线程安全1.6.2.1 同步与锁 由于线程间执行顺序不确定,非原子的操作很可能会被分割开从而影响运行的结果,这种情况下就需要加锁来保证共享的数据不会出现因竞争导致的错误。线程在访问数据前先试图获取锁,并在访问结束后释放锁,如果获取的锁已经被占用,则会等待直到可以获取锁。 常见的锁有二元信号量、互斥量、临界区和读写锁等。二元信号量(Binary Semaphore)就是单纯的锁,若非占用,则可被获取,否则不可被获取, 类似的,还有N元信号量互斥量(Mutex)和二元信号量很像,唯一的区别是信号量由A线程获取的锁可以由B线程释放,而其他线程是不能释放某线程申请的互斥量的临界区(Critical Section)与Mutex的区别是其他进程无法获取本进程创建的临界区,而这种获取对于Mutex是合法的。读写锁(Read-Write Lock) 多线程同时读取某数据总是没有问题的,但是若有某个线程试图修改,就必须同步操作避免出错。读写锁有共享和独占两个方式,可以简单的认为共享是读取标记而独占是修改 。条件变量(Condition Variable) 被限制线程要等待条件变量被唤醒才可以继续执行,以此实现线程的同步1.6.2.2 可重入 可重入指在某函数未执行完成的前提下,又一次进入该函数执行。通常是多线程同时执行这个函数或者函数递归调用自身,若一个函数不使用任何静态或全局的非const变量、不返回任何静态或全局的非const变量的指针,仅依赖Caller的参数,不依赖任何锁,调用的函数也都是可重入的,则这个函数称为可重入的1.6.2.3 过度优化 编译器在分析优化的过程中,可能会主动的改变程序的逻辑。落后的编译器技术可能已经无法满足日益增长的并发需求。书中举了两个很好的例子,记录在这里。 x = 0; Thread 1 Thread2 lock(); lock(); x ++; x ++; unlock(); unlock(); 由于有lock和unlock的保护,x++看上去并不会被并发破坏,执行完的结果似乎必然是2 。但是在编译器优化的过程中,很可能把x放到了某个寄存器里,因为线程之间的寄存器是独立的,那就可能存下下面这个情况: [Thread1] : 读取 x 的值到寄存器 AX (AX = 0) [Thread1] : AX ++ (由于之后还存在访问 x 的可能,为了效率先不会将 AX 写回 x) [Thread2] : 读取 x 的值到寄存器 BX(BX = 0) [Thread2] : BX ++ (BX = 1) [Thread2] : 将 BX 写回 x (x = 1) [Thread1]: ... [Thread1]: 将AX写回 x (x = 1) 可见,即使加了锁也不能保证线程安全。还有一个例子:x = y = 0; Thread1 Thread2 x = 1; y = 1; r1 = y; r2 = x; 阅读代码的结果似乎是显然的,r1和r2只少有一个为1,不可能同时为0,但是事实上,由于CPU存在动态调度,在执行的时候可能会将指令换序,编译器也可能为了效率而交换不想干的指令,这可能导致上述程序的实际执行是这样的x = y = 0; Thread1 Thread2 r1 = y y = 1; x = 1; r2 = x; 对于编译器,我们可以使用volatile关键字阻止优化,这里不展开记录。 同时,因为存在CPU的乱序执行现象,我们在执行new操作的时候,存在这样的两个步骤:分配内存调用构造函数 而在 pClass = new Class的时候,还存在一步将内存地址赋值给pClass的操作。但是赋值和调用构造函数的过程是可能被颠倒的,这回导致可能返回一个有意义的类指针的同时,相应的类还没有构造好,这时如果调用了对象,那可能会直接导致崩溃。 防止这种乱序操作的方式往往是添加一条CPU预先设置好的指令,如lwsync1.6.3 多线程内部情况1.6.3.1 三种模型一对一模型:每个用户线程一定对应一个内核线程(反之不适用,可能存在内核线程没有对应线程)。这种情况下线程是真正的并发,不会因为某个线程阻塞影响其他线程。使用clone和CreateThread创建的线程往往是这种模型。但是这样对内核线程数量的要求大,可能会使得用户线程数量受到限制,还有可能因内核调度导致效率下降多对一模型:一个内核线程对应多个用户线程,切换速度更快,但是一个线程阻塞会导致所有线程都无法执行。多对多模型:将多个用户线程映射到多个内核线程上,性能提升幅度不如一对一。
2021年09月07日
21 阅读
0 评论
1 点赞
2021-09-01
[开发/笔记]利用 Go-CQHTTP 实现对打卡情况的自动化汇报
作为班长,每天催打卡痛苦不堪。上学期用了来自 @TechCiel 的JLU-Health-Reporter 之后,我倒是轻松多了。假期临结束,导员催打卡痛苦不堪,所以让我推广自动打卡。我推广打卡还是痛苦不堪,因为各班交上来的信息参差不齐,有的不能正常打卡。也正当我想要做一个 QQ 机器人的时候。干脆结合一下,用 QQ 机器人每天汇报未能成功打卡以及爬取管理员查询到的未打卡情况。1. Go-CQHTTP 下载与配置 在 Mrs4s/go-cqhttp 下载 Release(Linux_AMD64)wget https://github.com/Mrs4s/go-cqhttp/releases/download/v1.0.0-beta6/go-cqhttp_linux_amd64.tar.gz tar -xzf go-cqhttp_linux_amd64.tar.gz rm -f go-cqhttp_linux_amd64.tar.gz file go-cqhttp > go-cqhttp: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped # 直接就是一个ELF,执行一下 # 会帮助生成配置文件,我选择的是HTTP协议,推荐可以直接使用HTTP # 填写好QQ号和密码这里提供一下我暂时使用的配置文件account: # 账号相关 uin: qqNum # QQ账号 password: 'passwd' # 密码为空时使用扫码登录 encrypt: false # 是否开启密码加密 status: 0 # 在线状态 请参考 https://docs.go-cqhttp.org/guide/config.html#在线状态 relogin: # 重连设置 delay: 3 # 首次重连延迟, 单位秒 interval: 3 # 重连间隔 max-times: 0 # 最大重连次数, 0为无限制 use-sso-address: true heartbeat: interval: 10 # heartbeat不一定要开,默认是5有点影响调试,我开到10 message: post-format: string ignore-invalid-cqcode: false force-fragment: false fix-url: false proxy-rewrite: '' report-self-message: false remove-reply-at: false extra-reply-data: false skip-mime-scan: false output: log-level: warn log-aging: 15 log-force-new: true debug: false # 开启调试模式 default-middlewares: &default access-token: 'passwd' # 事件过滤器文件目录 filter: '' rate-limit: enabled: false # 是否启用限速 frequency: 1 # 令牌回复频率, 单位秒 bucket: 1 # 令牌桶大小 database: # 数据库相关设置 leveldb: enable: true servers: - http: host: 127.0.0.1 port: 5700 timeout: 5 long-polling: enabled: false max-queue-size: 2000 middlewares: <<: *default # 引用默认中间件 post: - url: 127.0.0.1:5701 # 地址 secret: 'passwd' # 密钥screen -R cqhttp # 用screen把cqhttp和即将要写的机器人放后台 ./go-cqhttp curl 127.0.0.1:5700 > {"data":null,"msg":"API_NOT_FOUND","retcode":404,"status":"failed","wording":"API不存在"} # 已经成功部署, API可用再测试一下事件上报import json import socket HOST = "localhost" PORT = 5701 ADDR = (HOST, PORT) Server = socket.socket() Server.bind(ADDR) Server.listen(10) server, addr = Server.accept() print(server.recv(1024)) server.close()好用,包是一个 HTTP POST,Body 是一段 json至此,Go-CQHTTP 配置完毕2. QQ机器人编写讲道理,写这个其实还担法律风险,之前好多 QQ 机器人都被腾讯告了,本文只供研究技术使用,下载本文代码请于 24 小时内删除关于群内应用的 QQ 机器人,会在下一篇文章中进行描述。本文主要实现了调用 /send_group_msg API 来定时把自动打卡不成功的信息发到固定的QQ群里from time import time import requests file_path = "/home/Autosign/AutoSign/logs/" if (int(time()%86400/3600)+8)%24 == 10 : file_path += "Morning.log" else : file_path += "Night.log" # file_path = "tt.log" with open(file_path, "r") as log : for line in log : if "failed" in line : lcur = line.find("B")+8 rcur = line.rfind(":") message = line[lcur:rcur] print(message) data = { 'group_id' : foo, 'message' : message, 'auto_escape' : False } url = "http://127.0.0.1:5700/send_group_msg" rev = requests.post(url, data=data) 喜欢POST可以,API也同样支持GET
2021年09月01日
20 阅读
0 评论
1 点赞
2021-08-31
[应用/笔记]Typecho博客搭建
引言 高中时代OI博客选择的是Wordpress,当时是阿里云服务器+宝塔面板,一键配置。大学之后打算和OI生活Say Bye,同时又觉得Wordpress过于厚重,不是我喜欢的风格。加之CTF使我入门使用Linux,决定从零开始自己一步步搭建环境配置网站。CMS在Hexo和Typecho中纠结了一会,还是选择了内容发布更方便的Typecho。本文偏向记录而非教学向,可能存在一些走弯路或者描述不清楚、不准确的问题,在运维过程中遇到的问题也会持续更新。对于新手,还是比较建议使用宝塔一键部署+Wordpress这种,非常方便,不需要什么计算机知识。手动安装的优势在于知道自己每个参数、每个命令都做了什么,是不是有其他命令需要加载0 记录在这里的是之前就完成好了的工作:购买一个域名,我一开始是在namesilo上买的,便宜,后来转到了阿里云购买一个ECS/CVM/轻量应用服务器,我用的是一台2c4g的腾讯云CVM学生机域名备案,要么选择做ICP备案,要么选择国外VPS,推荐高中生选择后者,备案需要成年。但是备案也不算很麻烦域名解析,百度上有很多相关资料,只需要用比如阿里云的免费云解析DNS即可。或者还可以选用Cloudflare的免费套餐我购买了一个SQL服务器,这样LNMP中的M就可以外置1 环境配置1.1 环境配置 —— Linux 不必多说,云主机服务提供商都提供了一键还原镜像的功能,我这里选择的是CentOS 7.9,因为CentOS 8即将停止支持,而暂时不想使用Stream。其他Linux发行在配置上大同小异,主要是软件包管理器的区别。 重置好镜像之后,通过ssh连接服务器 ssh root@AAA.BBB.CCC.DDD 其中AAA.BBB.CCC.DDD是VPS的IP,会提示无法验证fingerprint,yes即可 然后输入你的root密码,在我的印象中,阿里云主机的默认用户不是root,那就把ssh @前面的用户名改成自己的用户名即可。输入密码全程密码是不可见的,不用担心没输入进去 镜像往往有一定的延迟更新,所以在CentOS上,我第一步选择了yum update更新本机系统以及软件包1.2 环境配置 —— Nginx Nginx我选择了编译安装的方式,一方面是比快速部署稳定,另一方面是可以自己添加组件 第一步安装一些编译安装需要依赖的库(zlib/brotli都是为了压缩,gzip和brotli二选一即可): yum -y install make gcc-c++ libtool git 在安装Nginx之前,先要安装PCRE,这是Nginx的Rewrite的依赖,安装的时候还不知道Rewrite是干嘛的,于是查了一下 URL Rewrite即URL重写,就是把传入Web的请求重定向到其他URL的过程。URL Rewrite最常见的应用是URL伪静态化,是将动态页面显示为静态页面方式的一种技术。比如http://www.123.com/news/index.asp?id=123 使用UrlRewrite转换后可以显示为http://www.123.com/news/123.html rewrite还能一定程度上的隐藏开发语言标记,提升安全性。在页面改扩展名后保持Pagerank 所以我们先来安装PCRE,同样选择编译安装,本文选择PCRE 8.45而非最新的PCRE 2 10.37cd /usr/local/src # 下载安装包 wget http://downloads.sourceforge.net/project/pcre/pcre/8.45/pcre-8.45.tar.gz # 解压安装包 tar -xzvf pcre-8.45.tar.gz cd pcre-8.45 # 编译安装 ./configure make && make install pcre-config --version 下载brotli包,brotli在速度和gzip基本相同的情况下,压缩率表现要比gzip更好# github 上 不 去, 只好fastgit了 git clone https://hub.fastgit.org/google/ngx_brotli.git cd ngx_brotli # 把config里面的submodule里的github也改成fastgit vim .git/config git submodule update --init 接下来安装OpenSSL,为了启用TLS 1.3 final,使用较新版本的OpenSSL, 这里使用的是OpenSSL 1.1.1lwget https://www.openssl.org/source/openssl-1.1.1l.tar.gz tar -xzvf openssl-1.1.1l.tar.gz mv openssl-1.1.1l openssl 接下来下载并编译Nginxwget https://nginx.org/download/nginx-1.20.1.tar.gz tar -xzvf nginx-1.20.1.tar.gz cd nginx-1.20.1/ # 如果需要支持 IE8 还需要在openssl-opt中添加enable-weak-ssl-ciphers # 这里还遇到了 recipe commences before first target的错误,查证后发现是configure的时候少了一个空格 ./configure --add-module=../ngx_brotli --with-openssl=../openssl --with-openssl-opt='enable-tls1_3' --with-http_v2_module --with-http_ssl_module --with-http_gzip_static_module --with-pcre=/usr/local/src/pcre-8.45 --prefix=/usr/local/webserver/nginx 使用systemd管理Nginx,主要是方便自启、开启关闭之类的vim /lib/systemd/system/nginx.service # 注意pid之类的文件位置是自己设置的[Unit] Description=The NGINX HTTP and reverse proxy server After=syslog.target network.target remote-fs.target nss-lookup.target [Service] Type=forking PIDFile=/usr/local/webserver/nginx/logs/nginx.pid ExecStartPre=/usr/local/webserver/nginx/sbin/nginx -t ExecStart=/usr/local/webserver/nginx/sbin/nginx ExecReload=/usr/local/webserver/nginx/sbin/nginx -s reload ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.targetsystemctl start nginx.service #开机自启 systemctl enable nginx.service此时访问ip应当可以看到nginx的欢迎页面接下来要配置Nginx配置文件vim /usr/local/webserver/nginx/conf/nginx.confuser nginx nginx; worker_processes 2; error_log logs/error.log crit; #error_log logs/error.log notice; #error_log logs/error.log info; pid logs/nginx.pid; events { accept_mutex on; multi_accept on; worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; server_names_hash_bucket_size 128; client_header_buffer_size 32k; large_client_header_buffers 4 32k; client_max_body_size 8m; fastcgi_intercept_errors on; #keepalive_timeout 0; keepalive_timeout 65; charset UTF-8; gzip_vary on; gzip_comp_level 6; gzip_buffers 16 8k; gzip_min_length 1000; gzip_http_version 1.0; gzip_types text/plain text/css application/json text/xml application/x-javascript application/xml+rss text/javascript application/javascript; #gzip on; brotli on; brotli_comp_level 6; brotli_types text/plain text/css application/json text/xml application/x-javascript application/xml+rss text/javascript application/javascript; include /www/mysite/conf/httpd.conf; }主要是配置了一下压缩1.3 环境配置 —— PHP在选择php版本的时候,我纠结了很久。Typecho的stable版本已经是17年的事情了,不支持php8.0,而时隔四年,终于在本文写的前一周作者决定大幅更新Typecho,使其支持php7.2-8.0,并且不向下兼容。但是开发版公布时间太短,安全性能难以得到保证。所以我还是选择用Stable版+php7.4的组合# 回到src目录下 cd /usr/local/src wget https://www.php.net/distributions/php-7.4.23.tar.gz # 虽说wget可以,但是我在下的时候比较慢,我选择本地梯子下好之后再sftp上传至服务器,ftp管理器使用的是filezilia,不需要使用ftp服务,直接sftp即可 tar -xzvf php-7.4.23.tar.gz cd php-7.4.23/ # 编译php # 这个配置来源于CSDN,这里面大部分的选项都是默认的选项,不过作者写了一遍,我也查了一遍。 yum -y install libxml2 libxml2-devel openssl openssl-devel curl-devel libjpeg-devel libpng-devel freetype-devel libmcrypt-devel libzip-devel sqlite-devel ./configure --prefix=/usr/local/php7 \ --with-config-file-path=/usr/loacl/php7/etc \ --with-config-file-scan-dir=/usr/local/php7/etc/php.d \ --with-pdo-mysql \ --with-mysqli \ --enable-mysqlnd \ --enable-fpm \ --with-iconv \ --with-zlib \ --enable-mbregex \ --with-fpm-user=nginx \ --with-fpm-group=nginx \ --enable-mbstring \ --enable-session \ --with-curl \ --with-jpeg \ --with-freetype \ --enable-xml \ --with-openssl \ --with-xmlrpc \ # 提示没有noniguruma yum install -y epel-release yum install -y oniguruma oniguruma-devel make make test make install 接下来要配置php-fpm/usr/local/php7/sbin/php-fpm [31-Aug-2021 14:06:22] ERROR: failed to open configuration file '/usr/local/php7/etc/php-fpm.conf': No such file or directory (2) [31-Aug-2021 14:06:22] ERROR: failed to load configuration file '/usr/local/php7/etc/php-fpm.conf' [31-Aug-2021 14:06:22] ERROR: FPM initialization failed提示没有配置文件,去网上扒一个改改告诉我只需要把default复制一份就可以了cd /usr/local/php7/etc cp php-fpm.conf.default php-fpm.conf cd php.conf.d cp www.conf.default www.conf再加一个systemctlvim /usr/lib/systemd/system/php-fpm.service内容[Unit] Description=The PHP FPM After=syslog.target network.target [Service] Type=forking PIDFile=/usr/local/php7/var/run/php-fpm.pid ExecStart=/usr/local/php7/sbin/php-fpm ExecReload=/bin/kill -USR2 $MAINPID PrivateTmp=true [Install] WantedBy=mutil-user.targetsystemctl daemon-reload systemctl start php-fpm1.4 环境测试用phpinfo测一下环境mkdir /www/mysite vim /www/mysite/conf/httpd.confserver { listen 80; listen [::]:80; index index.php index.html index.htm index.nginx-debian.html; root /www/mysite; location ~ .*\.php(\/.*)*$ { include fastcgi.conf; fastcgi_pass unix:/run/php/php7.2-fpm.sock; include fastcgi_params; } }vim /www/mysite/index.php<?php phpinfo(); ?>配置完毕后,访问ip仍然502。查看logcat /usr/local/webserver/logs/error.log2021/08/31 15:55:42 [crit] 18073#0: *39 connect() to unix:/run/php/php7.2-fpm.sock failed (2: No such file or directory) while connecting to upstream, client: 119.51.71.221, server: , request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/run/php/php7.2-fpm.sock:"一看这php7.2,发现是nginx配置有问题,把http部分(在网站目录中)的fast-cgi目录改掉,改成这样server { listen 80; listen [::]:80; index index.php index.html index.htm index.nginx-debian.html; root /www/mysite; location ~ .*\.php(\/.*)*$ { include fastcgi.conf; fastcgi_pass unix:/run/php-fpm.sock; include fastcgi_params; } }然后要更改php-fpm的配置文件,把www.conf中 listen = 127.0.0.1:9000改为listen=/run/php-fpm.socksystemctl reload php-fpm systemctl reload nginx崩溃,还是502,继续看log*47 connect() to unix:/run/php-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 119.51.71.221, server: , request: "GET / HTTP/1.1", upstream: "fastcgi://unix:/run/php-fpm.sock权限没给,去chmod一下chmod 777 /run/php-fpm.sockphpinfo正常显示了2. 站点配置2.1 DNS解析 当我们有域名之后,需要找一个解析服务提供商,随便找阿里云、腾讯云或者Cloudflare啥的都行,现在都是免费的,这一部分我不是本次操作的,不加以赘述。2.2 HTTPS证书 都2021年了,自然是要HTTPS的。小户人家用不起商业证书,还是得搞个自动续签的Let's Encrypt。我选择使用certbot来自动续签按照Certbot的官方指南,第一步要安装snapd分割线内是我踩过的坑 在前文中我们已经安装过epel,可以直接安snapd了yum install snapd systemctl start snapd.service snap install core ln -s /var/lib/snapd/snap /snap snap install --classic certbot ln -s /snap/bin/certbot /usr/bin/certbot 因为我的Nginx安装在/usr/local/webserver下,certbot找不到可执行文件,所以要加到PATH里vim ~/.bashrc加一行export PATH=/usr/local/webserver:$PATH没好用,加个软连接ln -s /usr/local/webserver/nginx/sbin /usr/bin/nginx ln -s /usr/local/webserver/nginx/conf /etc/nginx还是没好用,好好看了看报错,有一句The nginx plugin is not working; there may be problems with your existing configuration.看上去少个插件,pip3 install certbot-nginx然后是一个手动包管理的过程,也不知道pip抽什么风,无法解决依赖问题pip3 install wheel pip3 install setuptools_rust yum install rust yum install cargo到最后这都不好用,气的我直接把snapd卸载,还是yum香yum install certbot yum install python-certbot-nginx ln -s /usr/local/webserver/nginx/sbin /usr/bin/nginx ln -s /usr/local/webserver/nginx/conf /etc/nginx certbot --nginx中间会让你填邮箱域名什么的,按c取消之后会生成一个chain和一个key,至此,证书申请完毕,我们要到conf中补充上,就可以用了测试一下,在Chrome访问,域名左侧会有一把小锁,是https的提示2.3 站点Nginx配置更改之前写的httpd.conf如下,大部分都是certbot自动的server { index index.php index.html index.htm index.nginx-debian.html; server_name mysite; root /www/mysite; location ~ .*\.php(\/.*)*$ { include fastcgi.conf; fastcgi_pass unix:/run/php-fpm.sock; include fastcgi_params; } listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/mysite/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/mysite/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot }server { if ($host = mysite) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name mysite; return 404; # managed by Certbot } 2.4 下载部署Typecho在Typecho上下载官方正式版的包到/www/mysite因为是zip,我选择解压好用sftp直接上传访问mysite/install, 开始图形化安装需要提前在数据库中建好数据库和适当权限的账号,我选择的是腾讯云TDSQL-C。当然,不想用云数据库的也可以本地安装MySQL配置
2021年08月31日
76 阅读
0 评论
1 点赞
1
2
3