在上一篇中我们介绍了SQL简单语义分析概述ailx10:SQL简单语义分析概述zhuanlan.zhihu.com
本篇将和大家聊一聊SQL语义引擎中的指纹识别算法,这样也特别的绕,比XSS状态机还要绕,感兴趣的同学可以画画流程图,反正我是没有再画图了(不傻),采用GDB来分析的。
核心函数:int libinjection_sqli_fold(struct libinjection_sqli_state * sf)
疑难局部变量:size_t pos = 0; //下一个token的位置
left是已经折叠或处理的token数量的计数
我通读下来还是感觉有点困惑,所以准备写一篇GDB跟踪过程,欢迎提建议
step1:跳过最初的注释|左括号|一元运算符
第一次计算token
token.type取值TYPE_KEYWORD;TYPE_UNION;TYPE_GROUP;TYPE_EXPRESSION;TYPE_FUNCTION;TYPE_BAREWORD;TYPE_NUMBER;TYPE_VARIABLE;TYPE_STRING;TYPE_OPERATOR;TYPE_LOGIC_OPERATOR;TYPE_COLLATE;TYPE_RIGHTPARENS;TYPE_LEFTBRACE;TYPE_RIGHTBRACE;TYPE_DOT;TYPE_COMMA;TYPE_COLON;TYPE_SEMICOLON;TYPE_TSQL;TYPE_UNKNOWN;TYPE_EVIL;TYPE_FINGERPRINT;TYPE_BACKSLASH进入break分支,跳出当前循环。
token.type取值TYPE_NONE 直接跳出当前循环。
sf->current = &(sf->tokenvec[0]);
while (more) {
more = libinjection_sqli_tokenize(sf);
if ( ! (sf->current->type == TYPE_COMMENT || //'注释c' sf->current->type == TYPE_LEFTPARENS || //'左括号(' sf->current->type == TYPE_SQLTYPE || //'t' st_is_unary_op(sf->current))) { //一元运算符 + - ! ~ !! NOT break;
}
}
step2:准备处理下一个token
if (! more) {
/* 如果全是注释 左括号 一元运算符 ,那么直接退出*/
return 0;
} else {
/* 注意这里的 pos 是局部变量pos ,表示下一个 token 的位置*/
pos += 1;
}
step3.1:while(1)
如果pos>=5并且满足一定条件:
pos>5 令tokenvec[5]覆盖tokenvec[1] 再使得pos=2;left=0
pos=5 只令pos=1;left=0
如果pos<5 或 pos>=5 但是不满足一定条件 直接跳过这段处理。
if (pos >= LIBINJECTION_SQLI_MAX_TOKENS) {//5 if (
( sf->tokenvec[0].type == TYPE_NUMBER &&//'1' --> 1os1) | 1,s1) ) ||
( --> no(n) | no(1) ) ||
( --> 1),(1 ) ||
( --> n)o(n ))
{
if (pos > LIBINJECTION_SQLI_MAX_TOKENS)
{
st_copy(&(sf->tokenvec[1]), &(sf->tokenvec[LIBINJECTION_SQLI_MAX_TOKENS]));
pos = 2;
left = 0;
} else {
pos = 1;
left = 0;
}
}
}
step3.2:
if (! more || left >= LIBINJECTION_SQLI_MAX_TOKENS) {
left = pos;
break;
}
step4:第二次计算token
上一个token.type不等于TYPE_NONE;并且pos<=5;并且pos - left < 2
条件成立,sf->current指针指向第pos个token,然后计算 token
token.type不等于TYPE_NONE,
如果 token.type等于TYPE_COMMENT,用token覆盖last_comment,
如果不等于,last_comment.type置为NULL;pos +=1 ,准备计算下一个token
while (more && pos <= LIBINJECTION_SQLI_MAX_TOKENS && (pos - left) < 2) {
sf->current = &(sf->tokenvec[pos]);
more = libinjection_sqli_tokenize(sf);
if (more) {
if (sf->current->type == TYPE_COMMENT) {
st_copy(&last_comment, sf->current);
} else {
last_comment.type = CHAR_NULL;
pos &