CHƯƠNG 2. CƠ SỞ LÝ THUYÊT 7
2.6 Các công trình nghiên cứu liên quan
2.6.6 Software Defect Prediction via Convolutional Neural Net-
work
Dé tài nghiên cứu này tập trung vào việc trình bày một framework dự đoán
lỗi phần mềm thông qua việc sử dụng mô hình CNN để học các đặc trưng từ mã
nguồn chương trình. Framework này đã được thử nghiệm trên 7 dự án mã nguồn
mở khác nhau và đã gặt hái được kết quả ấn tượng, với hiệu suất F-measure vượt trội hơn so với các phương pháp truyền thống và phương pháp dựa trên
Deep Belief Networks (DBN).
Một trong những ưu điểm chính của framework này là khả năng học và trích
xuất các đặc trưng từ mã nguồn chương trình một cách tự động. Tuy nhiên, trong quá trình nghiên cứu, còn tồn tại một số thách thức cần được vượt qua. Đầu tiên, việc thu thập và xây dựng một tập dữ liệu lớn và đa dạng là cần thiết. Hiện tại, dataset vẫn chưa đủ lớn và thiếu tính khái quát, mô hình CNN hiện tại mới chỉ tập trung vào việc học các đặc trưng cục bộ trong mã nguồn, chưa
22
khai thác được các đặc trưng toàn cục hoặc toàn ngữ cảnh. Điều này có thể giới hạn khả năng phát hiện những lỗ hổng phần mềm mới [6].
Các công trình kể trên đều làm tốt một số phần trong việc tạo dựng ra hệ thống phát hiện lỗ hong phần mềm, nhưng ở một góc độ nào đó, nó sử dụng bộ dataset chưa đủ lớn, hoặc chưa ứng dụng lên đa dạng các mô hình. Nhận thấy điều này, nên nhóm chúng tôi quyết định nghiên cứu và xây dựng mô hình phát
hiện lỗ hổng phần mềm dựa trên CodeBERT được pre-trained trên source code.
23
CHƯƠNG 3. PHƯƠNG PHÁP THỰC HIỆN
Ỏ chương này chúng tôi sẽ trình bày cách triển khai, sử dụng mô hình xử lý
ngôn ngữ tự nhiên để trích xuất các đặc trưng của mã nguồn và các cách tiếp cận để huấn luyện mô hình học sâu, để phát hiện các lỗ hong phần mềm.
3.1. Hệ thống phát hiện lỗ hồng phần mềm
Tại phần này, nhóm sẽ nói về quy trình hoạt động của hệ thống phát hiện
lỗ hổng phần mềm kết hợp giữa mô hình ngôn ngữ tự nhiên đóng vai trò tạo embedding và mô hình deep learning để học và thực hiên phát hiện lỗ hong phan
mềm.
Nghiên cứu này có hai giai đoạn: giai đoạn học tập (nghĩa là training phase)
và giai đoạn phát hiện (nghĩa là tiến hành test lại quá trình học). Đầu vào của
giai đoạn training là một số lượng lớn các mã nguồn chương trình dùng để đào tạo, một số chương trình chứa lỗ hổng phần mềm và những chương trình khác thì không. "Lỗ hổng" có nghĩa là một chương trình chứa một hoặc nhiều lỗ hồng
đã biết. Đầu ra của giai đoạn training là các mô hình deep learning đã được
huấn luyện với các đặc trưng của các đoạn code có chứa 16 hồng phần mềm va sẵn sàng thực thi nhiệm vụ phát hiện lỗ hồng phần mềm.
3.1.1. Giai đoạn huôn luyện
Về tổng thể, giai đoạn này có 3 bước chính
1. Trích xuất các code gadgets từ mã nguồn chương trình đầu vào
2. Embedding các code gadgets đó để chuyển thành các vector
24
3. Dùng các vector vừa nhận được làm đầu vào cho việc huấn luyện mô hình
deep learning
Tiếp theo sẽ đến với phần chỉ tiết của giai đoạn này với 3 bước chính ban đầu đưa chia làm 8 bước nhỏ:
1. Đầu tiên tại bước 1, để chuẩn bị cho quá trình trích xuất, đầu tiên sẽ xử
lý đầu vào là các file mã nguồn (Hình 3.1). Mô hình tiến hành loại bỏ các phần bình luận (comment) cũng như các ký tự không thuộc bảng mã ASCII
trong các file mã nguồn đó để quá trình trích xuất code gadgets được diễn
ra trơn tru, đạt hiệu quả cao, tránh sự nhập nhằng trong việc xử lý các
đoạn mã.
2. Tiếp theo tại bước 2, chúng ta sẽ trích xuất library/API function calls.
Để tăng tính hiệu quả của việc trích xuất này, mô hình sẽ phân loại các
library/API function calls thành hai loại: forward library/API function calls
va backward library/API function calls.
Forward library/API function calls là những lệnh gọi hàm nhận trực
tiếp một hoặc nhiều đầu vào từ bên ngoài. Ví dụ, lệnh gọi hàm "recv"
là một forward library/API function calls vì nó nhận dữ liệu trực tiếp từ socket. Trong khi đó, backward library/API function calls là những
13 main(int argc, char **argv) 13 main(int argc, char **argv)
15 char *userstr; 15 char *userstr;
18 userstr = argv[1]; 18 userstr = arw[1];
19 test(userstr); 19 test(userstr);
2_ test(char *str) 2_ test(char *str)
4 int MAXSIZE=40; 4 int MAXSIZE=40;
5_ char buf[MAXSIZE]; 5_ char buf[MAXSIZE];
9 strcpy(buf, str); /*string copy*/ 9 strcpy(buf, str);
Input: code gadget (from Step II.1) (1) Remove non-ASCII
characters and comments
13 main(int argc, char **argv) 13 main(int argc, char **argv)
15 char *VAR1; 15 char *VAR1;
18 VAR1 = argy[1]; 18 VAR1 = arg[1];
19 test(VAR1); 19 FUN1(VAR1);
2_ test(char *VAR2) 2_ FUN1(char *VAR2)
4 intVAR3=40; 4 int VAR3=40;
5_ cha VAR4[VAR3]; 5_ char VAR4[VAR3];
9_ strcpy(VAR5, VAR2); 9 strcpy(VAR5, VAR2);
(2) Map user-defined variables (3) Map user-defined functions
Hình 3.1: Quá trình xử ly mã nguồn chương trành đầu vao.
25
lệnh gọi hàm không nhận bất kỳ đầu vào nào từ bên ngoài. Ví dụ, lệnh gọi
hàm "strepy" trong hình 3 là một backward library/API function calls vì
nó không nhận trực tiếp bất kỳ đầu vào bên ngoài chương trình.
. Sở di phải phân loại rõ ràng 2 loại lệnh gọi ham này bởi vì khi trích xuất đối với mỗi đối số trong forward library/API function calls, mô hình sé tạo ra một hoặc nhiều forward slices, trong đó đoạn cuối tương ứng với trường hợp
mà đoạn liên quan đến đối số được phân nhánh sau library/API function calls. Dối với mỗi đối số trong backward library/API function calls, mô hình tạo ra một hoặc nhiều backward slices, trong đó đoạn cuối tương ứng với trường hợp mà nhiều đoạn liên quan đến đối số được hợp nhất trước lệnh
gọi thư viện/hàm API.
. Ở bước trước, chúng ta đã tạo ra các phần chương trình tương ứng với các
slices code (cả forward và backward) từ library/API function calls. Bay giờ
chúng ta sẽ tap hợp các phần chương trình này thành các code gadget. Dé
tạo code gadget, đầu tiên, chúng ta sẽ xác định các câu lệnh thuộc cùng một hàm mà người dùng đã định nghĩa, và sau đó chúng ta sẽ kết hợp các câu lệnh này thành một phần chương trình duy nhất theo thứ tự xuất hiện trong hàm đó. Nếu có sự trùng lặp giữa các câu lệnh, chúng ta sẽ loại bỏ
các câu lệnh trùng lặp đó (Hình 3.2).
. Ở bước 5, chúng ta tiến hành đánh nhãn cho từng code gadget một cách
thủ công. Việc này được thực hiện dựa trên các mẫu lỗ hổng từ các nguồn như SARD và NVD. Mục đích của việc đánh nhãn là để kiểm soát và xác định các dạng lỗ hồng có trong tập dữ liệu. Qua quá trình đánh nhãn thủ
công, chúng ta đảm bảo rằng các code gadget được phân loại đúng, tránh
các trường hợp sai sót dẫn đến việc phát hiện lỗ hồng giả (false positive).
Sau khi hoàn thành việc đánh nhãn thủ công cho một phan của bộ dữ liệu, chúng ta sẽ tiếp tục quá trình đánh nhãn phan còn lại của bộ dit liệu bằng
phương pháp tự động.
26
void pri ntln(const char * In)
{
if(In != NULL) printf("%s\n", In);
oid func()
char *data;
char dataBuffer[100];
char source[100];
me mset(dat aBuffer, 'A', 99);
dat aBuffer[99] = "\0';
while(1)
{
void println(const char * In)
{ iffifẽ!= NULL)
¡_ EERE'Xewr[Dỷ
‘oid func()
œx*O®UtbU NiVị{
9_ char *data;
10 char dataBuffer[100];
11 char source[100];
1213 TH In DU 'A',98);
14 [99] =\0';
45, =:
16 while(1)
7 void func()
9 char *data;
10 char dataBuffer[100];
11 char source[100];
13 memset(dataBuffer, 'A', 99);
14 dataBuffer[99] = '\0';
16 while (1)
18 data = dataBuffer - 8;
22 memset(source, 'C', 99);
23 source[99] = "\0';
24 memmove (data, source, 100*sizeof(char));
25 data[99] = '\0';
26 printin(data);
1 void println(const char * In)
data = dataBuffer - 8;
break;
}
Hành 3.2: Vi dụ vé quá trinh trích xuất code gadgets từ mã nguồn chương trình
6. Ở bước 6 tiếp theo, chúng ta sẽ thực hiện quá trình embedding (nhúng) cho
các code gadget sử dụng hai mô hình khác nhau: Word2Vec và CodeBERT.
Phương pháp embedding này nhằm chuyển đổi các code gadget đã được
đánh nhãn thành các vector đại diện cho từng token trong code gadget đó.
Trong quá trình embedding, đầu vào sẽ là các code gadget đã được gán nhãn, và đầu ra là các vector đại điện tương ứng. Mỗi token trong code
gadget sẽ được biểu diễn bằng một vector, tập hợp các vector đó sẽ biểu
diễn được toàn vẹn một code gadget, trong đó các thông tin quan trọng về cấu trúc và nghĩa của code sẽ được mô tả dưới dạng các giá trị số. Phương
pháp embedding Word2Vec sẽ xây dựng các vector biểu diễn bằng cách ánh
xạ từng từ trong code gadget thành một vector dựa trên ngữ cảnh xuất hiện của từ đó trong tập dữ liệu. Điều này cho phép Word2Vec bắt capture mối quan hệ ngữ nghĩa và ngữ cảnh giữa các từ trong code gadget. Mô hình CodeBERT sử dụng một phương pháp nhúng mã nguồn mã hóa ngữ nghĩa
của code. Nó tao ra các vector biểu diễn bằng cách sử dung mạng nơ-ron biến đổi mã nguồn thành các vector số hóa dựa trên khả năng hiểu và mô
hình hóa cấu trúc ngữ nghĩa của code.
7. Sau quá trình embedding cả hai mô hình Word2Vec và CodeBERT đều trả
27
về các vector chứa thông tin quan trọng về cấu trúc và nghĩa của code
gadget, giúp mô hình deep learning có thể làm việc trên dữ liệu đã được vector hóa để phát hiện lỗ hổng phần mềm.
8. Output của quá trình embedding trên sẽ là tập vector với kích thước (x,y,z)
với một vector trong đó có dạng như sau:
XI X2 X3 ..- Nya Xự
X2 XI X2 ..- ÄXụ Xy4
V=
X, Xp Xp có X2 XI
Phần huấn luyện mô hình trong dé tài (Hình 3.3) tập trung vào xây dựng
và đào tạo một loạt các mô hình deep learning để phát hiện 16 hong phần mềm.
Chúng tôi sử dụng bốn mô hình khác nhau, gồm CNN, RNN, Transformer va
BiLSTM, để khám phá và hiểu các đặc trưng quan trọng trong đoạn mã nguồn.
Mô hình CNN được thiết kế để phân tích không gian của đoạn mã và tìm ra các mẫu quan trọng. Chúng tôi sử dụng các lớp tích chập và lớp gộp để trích
xuất thông tin cục bộ từ đoạn mã. Mô hình RNN giúp chúng tôi mô hình hóa thông tin chuỗi trong đoạn mã và nhận biết mối quan hệ giữa các câu lệnh. Mô
hình Transformer sẽ giúp chúng tôi hiểu các mối quan hệ phi cấu trúc giữa các
từ hoặc câu lệnh trong đoạn mã. Cuối cùng, mô hình BiLSTM kết hợp thông tin
từ cả quá khứ và tương lai để hiểu được ngữ cảnh và mối quan hệ trong đoạn
mã, dưới đây là chi tiết của 4 mô hình.
Stage 1: Extract code gadgets
output
Remove comment and | alls. [9 strepy(buf, str);
non-ASCll charactor |_|
Extracting libraryIAPI function
string copy"!
A
Transforming program slices into code gadgets
7 void funel)
9. char “data
10 char dataBufer[100];
11 chất ứurce[1):
13 memsetđataBuffe.'A', 9);
14 data8ufel98]= 10;
16 while (1)
18 data= databutter- 8,
33 memsetisource,
23 sowcel93)=
labeling
Stage 2: Embedding code
gadget to vector
Token [Vector] vector of symbolic
Stage 3: Traning model
each code
Code gadget Code gadget 1
‘Code gadget 2
gadget Tas] [okt | [oka ‹s. [eka] Gers]
(Code gadget 3
L4,
code gadgets
Transforming code gadgets into vectors
as, SP eee
Embedding code gadget
Hình 3.3: Giai đoạn huấn luyện.
Traning deep learning
model
Deep learning’ neural network with fine-tuned model
parameters
Âo /
Sẽ
29
3.1.1.1. CNN
Dây là mô hình CNN (Convolutional Neural Network) được sử dung trong
việc phát hiện lỗ hong phần mềm. Dưới đây là giải thích về từng lớp trong mô
hình:
e Lớp Conv1D: Lớp này thực hiện phép tích chập 1D trên đầu vào. Nó sử
dụng bộ lọc (filters) có kích thước 3 và ham activation ReLU để tạo ra các đặc trưng từ dit liệu đầu vào. Dau vào của lớp Conv1D có kích thước
(vectors.shape|1], vectors.shape[2]).
e Lớp MaxPooling1D: Lớp này thực hiện phép lay mau tối da trên đầu ra của
lớp Conv1D. Nó giúp giảm kích thước không gian của đặc trưng và trích
xuất thông tin quan trọng.
e Lớp Flatten: Lớp này được sử dụng để chuyển đổi đầu ra của lớp trước
thành một vecto 1 chiều (flattened vector) để chuẩn bị cho việc kết nối day
đủ (fully connected) với các lớp tiếp theo.
e Lớp Dense: Lớp này thực hiện phép kết nối đầy du (fully connected) với các
đơn vị an. Đầu tiên, lớp Dense có 100 đơn vi an và sử dụng ham activation
ReLU.
e Lớp Dropout: Lớp nay 4p dụng phép dropout với tỷ lệ dropout là 0.5 để
ngẫu nhiên drop một phần đơn vị đầu vào và hạn chế overfitting.
e Lớp Dense: Lớp này có 2 đơn vị đầu ra va sử dung hàm kích hoạt softmax
để dự đoán xác suất của các lớp đầu ra (2 lớp trong trường hợp này).
Tổng quát, mô hình CNN (Hình 3.4) bao gồm các lớp Conv1D để trích xuất đặc trưng từ dữ liệu, các lớp MaxPooling1D để giảm kích thước không gian của đặc trưng, lớp Flatten để chuyển đổi đầu ra thành vectơ 1 chiều, các lớp Dense
để tạo ra các đơn vị an và dự đoán xác suất đầu ra, và lớp Dropout để hạn chế
overfitting trong quá trình huấn luyện.
30
convid_input | input: | [(None, 50, 50)]
InputLayer | output: | [(None, 50, 50)]
conv1d me] (None, 50, 50)
Conv1D | output: | (None, 48, 64)
Y
max poolingid | input: | (None, 48, 64) MaxPooling1D | output: | (None, 24, 64)
Ỷ
max poolingld 1 | input: | (None, 22, 64)
MaxPooling1D | output: | (None, 11, 64)
(ẹone, 11, 64) (None, 704)
(None, 704)
output: | (None, 100) |
| Dense
(None, 100)
(None, 100) Dropout
(None, 100) (None, 2)
Hình 3.4: Kiến trúc mô hành CNN
3.1.1.2. BiLSTM
Mô hình BiLSTM trong nghiên cứu có cấu trúc như Hình 3.5, bao gồm:
e Bidirectional LSTM: Mô hình sử dụng một lớp Bidirectional LSTM (BiL-
STM) cho phép học cả thông tin từ các ngữ cảnh trước và sau của mỗi
chuỗi đầu vào. Các đầu vào của BILSTM có kích thước (vectors.shape[1],
vectors.shape|2]), trong đó vectors.shape[l] đại diện cho độ dài của mỗi
chuỗi đầu vào và vectors.shape[2] đại diện cho số chiều của vector biểu
điễn.
31
| bidirectional_input input: | (None, 50, 50)]
| InputLayer output: | (None, 50, 50)]
bidirectional(Istm) [mm (None, 50, 50)
Bidirectional(LSTM) | output: | (None, 600)
Ỷ
dense | input: | (None, 600) Dense | output: | (None, 300)
Ỷ
leaky re lu | input: | (ẹone, 300) LeakyReLU | output: | (None, 300)
Ỷ
dropout | input: | (None, 300) Dropout | output: | (None, 300)
Ỷ
đense 1 | input: | (None, 300) Dense | output: | (None, 300)
Ỷ
input: | (None, 300) output: | (None, 300)
leaky re ]u 1 LeakyReLU
Ỷ
dropout_1 | input: | (None, 300) Dropout | output: | (None, 300)
y
dense_2 | input: | (None, 300) Dense | output: | (None, 2)
Hình 3.5: Kiến trúc mô hành BiLSTM.
e Dense: Sau lớp BiLSTM là một lớp Dense với 300 đơn vị để ánh xạ từ không
gian đặc trưng tạo bởi BiLSTM sang không gian có kích thước 300.
e LeakyReLU: Lớp LeakyReLU được sử dụng để thực hiện hàm kích hoạt
Leaky ReLU (Rectified Linear Unit) với một hệ số rò rỉ nhỏ dương khi đầu
vào âm, giúp tránh hiện tượng đóng băng gradient và tăng khả năng học của mô hình.
e Dropout: Đây là một lớp Dropout với tỷ lệ dropout là 0.5, được áp dụng để
ngẫu nhiên drop đi một phan đơn vi đầu vào, nhằm giảm overfitting trong quá trình huấn luyện.
e Dense: Tiếp theo, sử dụng một lớp Dense với 300 đơn vị và hàm kích hoạt
LeakyReLU để tạo ra một tầng trung gian khác có kích thước 300.
32
e Dropout: tiếp tục áp dung một lớp Dropout với tỷ lệ dropout là 0.5 để giảm
overfitting.
e Dense: Cuối cùng, sử dung một lớp Dense với 2 đơn vi và ham activation
softmax, đại diện cho đầu ra của mô hình. Hàm softmax được sử dụng để chuyển đổi đầu ra thành xác suất dự đoán cho hai lớp.
Tổng quan, mô hình sử dụng một lớp BiLSTM để học thông tin từ các ngữ cảnh trước và sau của chuỗi đầu vào, sau đó ánh xạ sang không gian đặc trưng và sử
dụng các lớp Dense với LeakyReLU và Dropout để tạo ra một tầng trung gian
và đầu ra dự đoán.
3.1.1.3. RNN
Mô hình RNN có kiến trúc tương tự với mô hình BiLSTM chi thay thé lớp
Bidirectional(LSTM) thành SimpleRNN (Hình 3.6).
8.1.1.4. Transformer
Day là mô hình Transformer[11] được sử dung trong việc phát hiện lỗ hồng
phần mềm. Dưới đây là giải thích về từng khối trong mô hình:
e Khối Transformer: Mô hình sử dụng 3 khối Transformer giống nhau để xử
lý dữ liệu đầu vào. Mỗi khối Transformer bao gồm các thành phần sau:
e MultiHeadAttention: Lớp này thực hiện attention mechanism với số lượng
head là 8 và kích thước của key là 32. Nó áp dung attention trên đầu vào
và tính toán đầu ra.
e LayerNormalization: Lớp này thực hiện chuẩn hóa dữ liệu đầu ra của at-
tention mechanism để điều chỉnh độ lớn của đặc trưng.
e Dense: Lớp này có units=32 và activation=’relu’, được sử dung để biến đổi
dữ liệu đầu ra của attention mechanism.
33
simple mn input | input: | [(None, 50, 50)]
InputLayer output: | [(None, 50, 50)]
Ỷ simple_mn | input: | (None, 50, 50) SimpleRNN | output: | (None, 300)
Ỷ dense | input: | (None, 300) Dense | output: | (None, 300)
Ỷ
leaky re lu | input: | (None, 300) LeakyReLU | output: | (None, 300)
Ỷ dropout | input: | (None, 300) Dropout | output: | (None, 300)
Ỷ đense 1 | input: | (None, 300) Dense | output: | (None, 300)
Ỷ leaky re lu 1 | input: | (None, 300) LeakyReLU | output: | (None, 300)
v dropout_1 | input: | (None, 300) Dropout | output: | (None, 300)
Ỷ dense 2 | input: | (None, 300) Dense | output: (None, 2)
Hinh 3.6: Kiến trúc mô hành RNN.
e Dense: Lớp này có units=50 và không có activation funetion, để tạo ra đầu
ra cuối cùng của khối Transformer.
e Lớp Pooling: Lớp GlobalAveragePooling1D được sử dụng để tính toán giá
trị trung bình của mỗi chiều trong đầu ra của khối Transformer cuối cùng.
Nó giúp giảm kích thước không gian của dữ liệu và trích xuất thông tin
quan trọng.
e Lớp Dầu ra: Lớp Dense với units=2 và activation=’softmax’ được sử dụng
để dự đoán xác suất của các lớp đầu ra (2 lớp trong trường hợp này).
Tổng quát, mô hình Transformer (Hình 3.7) dùng các khối Transformer để xử
lý dit liệu đầu vào, áp dụng attention mechanism để tạo ra các đặc trưng quan trọng, sau đó sử dụng lớp Pooling để giảm kích thước không gian và trích xuất thông tin quan trọng, cuối cùng sử dụng lớp Dense để dự đoán xác suất đầu ra.