Yak语言基础

Yakit使用的是Yak语言,所以在写插件之前需要学习一下Yak语言(感觉比较像Python和JavaScript)

变量与数据类型

变量

Yak中赋值符为:=

定义变量

使用var作为关键词,var后使用空格作为分隔符即可定义变量

1
2
3
var a            // 声明变量a
var b, c // 声明变量b和c
var d, e = 1, 2 // 声明变量d和e,并分别赋值为1和2

在没有var修饰的时候,赋值符“=”会为左边的“标识符”自动创建一个变量

基础数据类型

  • int:表示可以带正负号的整数数据类型(在Yak语言中占用的大小为64位);
  • string:用于表示一系列字符数据的,字符串中可以使用转义字符,例如\n等;
  • float:用于表示浮点数;
  • byte:等同于“无符号8位整数”,通常用来表示一个“字节”,类似C语言中的Char类型;
  • nilundefined一般用于表示一个未定义的变量或者空值;
  • bool:表示“布尔值”,其值只有两种情况,truefalse

Tips:

声明一个非十进制的整数

1
2
3
4
5
6
7
8
// 二进制声明
a = 0b10 // a赋值2

// 八进制声明
b = 0100 // b赋值64

// 十六进制声明
d = 0x10 // d赋值16

多行文本

可以使用``(反引号)来定义多行文本,此时会忽略文本中的转义符号

1
2
3
4
5
6
7
8
9
10
abc = `Hello World\n
Hello Yak`
println(abc)

/*
Output:

Hello World\n
Hello Yak
*/

格式化字符串

Yak语言使用%进行基本的字符串格式化。格式化字符串的两种用法和操作基本语法:

  1. printf函数:第一个参数为需要格式化的字符串模版,其余参数为为格式化字符串中的参数;

  2. %格式化操作符:

    • %左边为需要格式化的模版,右边为一个格式化字符串的参数,例如 "Hello %v" % "World"

    • 如果有多个需要格式化的点,那么需要使用 []来包裹,并用逗号分隔元素,例如:"My name is %v, I am %d years old" % ["John", 18]

示例:

1
2
3
4
5
6
7
8
9
printf("Hello I am %d years old\n", 18)
println("Hello %v + %05d" % ["World", 4])

/*
OUTPUT:

Hello I am 18 years old
Hello World + 00004
*/

格式化字符串中的占位符

字符串中的占位符 解释
%v 根据变量的类型自动选择格式。
%T 输出变量的类型。
%d 十进制整数。
%b 二进制整数。
%o 八进制整数。
%x 十六进制整数,使用小写字母。
%X 十六进制整数,使用大写字母。
%f 浮点数,不带指数部分。
%c ASCII码对应的字符。
%q 带引号的字符或字符串。
%s 字符串。
%p 输出十六进制表示的内存地址或引用。

字符串模版字面量

​ 类似于Python,在字符串的前面加上一个小写的 f,然后在字符串内部用 ${} 包裹需要插入的表达式。

示例:字符串中插入变量 aname 的值。

1
println(f`Hello ${a}, Hello ${name}`)

其他数据类型

列表类型:List

在 Yak 语言中,List 是一种动态数组,它可以存储和管理相同类型的元素。Yak 语言支持字面量声明和 make 语法来创建 List

字面量创建列表:使用 [var1, var2, var3...] 形式快速声明一个 List。Yak 语言会根据列表内的元素类型自动推断合适的 List 类型。

**字典类型:**map

字典用于存储键值对

字面量创建字典示例:

1
m = {"a": 1, "b": 2}
**通道类型:**channel

通道类型用于多线程之间的数据共享

创建与声明:使用make函数来创建一个新的channel。这就像是开设一个新的邮局,用于发送和接收包裹。

1
2
ch := make(chan int)      // 创建一个没有存储空间的int类型的channel
ch2 := make(chan var, 2) // 创建一个有2个存储空间的var类型的channel

数据写入

1
2
3
ch <- 1      // 将一个整数1寄出到ch,但是因为 ch 在上文创建时没有声明存储空间,这里会阻塞
ch2 <- "a" // 将一个字符串寄出到ch2
ch2 <- 0 // 将一个整数0寄出到ch2

读取数据

1
v := <-ch    // 从ch取走一个包裹

Tips:判断数据是否取走

1
2
3
4
5
6
v, ok := <-ch
if ok {
println("取走成功,值为:", v)
} else {
println("邮局已关闭")
}

Channel的属性

Yak提供了一些内置的函数来检查channel的当前状态。

1
2
len(ch2)   // 查看ch2中还有多少个包裹
cap(ch2) // 查看ch2最多能存放多少个包裹

关闭Channel

关闭后的channel不能再寄出数据,但仍然可以从中取走数据。

1
close(ch2)

运算符

数学运算

数学运算包括加、减、乘、除和取余等操作:

1
2
3
4
println(2 + 2)    // 输出: 4
println(50 - 5*6) // 输出: 20
println(8 / 5) // 输出: 1
println(17 % 3) // 输出: 2

逻辑运算符

逻辑运算符在Yak语言中用于进行逻辑操作,包括逻辑与(&&)和逻辑或(||)

这两个运算符都具有短路特性,即如果左侧的操作数已经能确定整个表达式的值,那么就不会再计算右侧的操作数

1
2
3
4
5
a = true
b = false

println(a && b) // 输出:false
println(a || b) // 输出:true

三元逻辑运算符

形式为condition ? value1 : value2

如果condition为真,则表达式的结果为value1,否则为value2。这个运算符也具有短路特性,即如果条件已经能确定整个表达式的值,那么就不会再计算其他的值。以下是一些使用示例:

1
2
a = 5b = 3
result = a > b ? a : bprintln(result) // 输出:5

控制与循环

这部分比较像Python,直接写示例就好了

条件判断

示例:

1
2
3
4
5
6
7
8
9
10
11
12
x = 88; // 学生的成绩
if x >= 90 {
print("非常优秀");
} else if x >= 80 {
print("优秀");
} else if x >= 70 {
print("良好");
} else if x >= 60 {
print("普通");
} else {
print("不及格");
}

SWITCH 语句

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
grade = 'B'
switch (grade) {
case 'A':
println("优秀");
case 'B':
println("良好");
case 'C':
println("合格");
case 'D':
println("需要努力");
default:
println("无效的成绩");
}

此外,switch允许一个case分支匹配多个值

For循环

定义:

1
2
3
for 表达式1 ; 表达式2 ; 表达式3 {
循环体
}

首先运行表达式1 -> 判断表达式2,如果成立则运行循环体中的代码 -> 每一次循环后执行表达式3 -> 进行表达式2的判断并循环执行,直到表达式2判断为假,则结束整个函数。

TIPS:

简化的For循环

对于无初始化表达式和每次循环后的迭代表达式的for循环,可以写为:

1
2
3
for 布尔表达式 {
循环体
}

遍历列表

使用for-range与使用for-in效果相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
for i, v = range a {
println(i, v)
}

//等同于

for v in a {
println(v)
}

/*
OUTPUT:
0 a
1 b
2 c
3 d
*/
  • i, v是我们在每次迭代中定义的两个变量,其中i将存储当前的索引,而v将存储与该索引对应的值(若只迭代一个变量,迭代的值将会是索引)。
  • range a是一个表达式,它创建了一个从集合a中提取索引和值的范围。

遍历字典

使用for-range/for-in遍历字典,这样可以同时获取键和值:

1
2
3
4
5
6
7
8
9
for k, v = range b {
printf("%s:%d, ", k, v)
}

//等同于

for k, v in b {
printf("%s:%d, ", k, v)
}

在这个循环中,kv分别在每次迭代时被赋予字典中的键和对应的值

遍历通道

遍历通道中的数据可以使用for-range/for-in语句来实现这一点:

1
2
3
4
5
6
7
8
9
for result = range ch { // 遍历通道内的数据
println("fetch chan var [ch] element: ", result)
}

//等同于

for result in ch { // 遍历通道内的数据
println("fetch chan var [ch] element: ", result)
}

直接指定循环次数

1
2
3
for in n {
// 循环体将执行n次
}

如需当前的索引:

1
2
3
for i in n {
// 可以使用变量i,它从0开始,直到n-1
}

或使用range关键字:

1
2
3
for range n {
// 循环体将执行n次
}

如果需要索引,可以将irange一起使用(注意:range 前有一个 =):

1
2
3
for i = range n {
// 可以使用变量i,它从0开始,直到n-1
}

插件

Yakit的插件基本可以分成三种类型:交互式插件(Yak原生插件)、MITM 插件、Codec插件

交互式插件类似于单开一个功能页面

MITM 插件用于被动扫描时对漏洞进行检测

Codec插件用于对数据包进行操作,可以设置右键调用,对HTTP数据进行变形

API

Yakit插件编写提供的API

API手册 | Yak Program Language

几个比较经常用到的API

https://yaklang.com/api-manual/api/cli (用于输入插件所需的数据)

https://yaklang.com/api-manual/api/codec (Crypto等操作)

https://yaklang.com/api-manual/api/poc (获得、修改数据包等操作)


本站由 Wells 使用 Stellar 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。