2019 360杯 re wp--Here are some big nums
测试文件:https://www.lanzous.com/i7303oh
1.准备
获取信息:
- 32位文件
2.IDA打开
找到主函数之后,反编译为伪C代码
int sub_404D70()
{
int result; // eax
char v1; // [esp+0h] [ebp-58h]
char v2[]; // [esp+18h] [ebp-40h]
char v3; // [esp+28h] [ebp-30h]
char v4[]; // [esp+2Ch] [ebp-2Ch]
char v5; // [esp+3Ch] [ebp-1Ch]
int v6; // [esp+40h] [ebp-18h]
size_t v7; // [esp+44h] [ebp-14h]
int i; // [esp+48h] [ebp-10h]
int v9; // [esp+54h] [ebp-4h] sub_404EF0("------360CTF------\n", v1);
sub_404EF0("Please input fl@g:", v1);
sub_404F30("%s", (unsigned int)Str);
v7 = strlen(Str);
if ( v7 == )
{
sub_401F20(&v1);
v9 = ;
for ( i = ; i < ; ++i )
{
v4[i] = Str[i];
v2[i] = byte_4080A8[i];
}
v5 = ;
v3 = ;
if ( (unsigned __int8)((int (__cdecl *)(char *, signed int))loc_404600)(v4, ) && (unsigned __int8)sub_404860(v2) )
{
sub_404EF0("Congratulations!!!", v1);
system("PAUSE");
v9 = -;
sub_401FD0(&v1);
result = ;
}
else
{
sub_404EF0("Wrong!!!", v1);
v6 = ;
v9 = -;
sub_401FD0(&v1);
result = v6;
}
}
else
{
sub_404EF0("wrong format!!!", v1);
result = ;
}
return result;
}
从第18行代码,我们能够得知flag(输入字符串)长度应该为32
代码的第26行loc_404600(v4, 16) && sub_404860(v2)很明显就是我们需要关注的两个函数,但是打开loc_404600(v4, 16)
.text: loc_404600: ; CODE XREF: sub_404D70+D3↓p
.text: ; DATA XREF: TlsCallback_0:loc_404552↑o ...
.text: cmp ch, ah
.text: mov ds, word ptr [edx+edx*]
.text: push es
.text: adc [ecx], ebp
.text: sub eax, 6DD7066Eh
.text:0040460D outsb
.text:0040460E bound esi, [esi+3Dh]
.text: or ch, bl
.text: push ebx
.text: insd
.text: outsb
.text: bound esi, [esi-14h]
.text: adc dl, 76h
.text:0040461C insd
.text:0040461D outsb
.text:0040461E movsd
.text:0040461F xor eax, [ecx+6D76626Eh]
.text: push es
.text: cdq
.text: pop ss
.text: sub eax, 0E13BEF6Eh
.text:0040462D xchg bh, [esi+ebp*]
.text: xchg eax, edx
.text: xchg eax, ecx
.text: movsd
.text: xor edx, [ecx+6D76626Eh]
.text: push es
.text:0040463A inc ecx
.text:0040463B adc al, 2Dh
.text:0040463D outsb
.text:0040463E out dx, eax
.text:0040463F cmp ecx, ecx
.text: xchg ch, [eax]
.text: scasb
.text: xchg eax, edx
.text: xchg eax, ecx
.text: movsb
.text: xor edx, [ecx+0F160A6Fh]
于是尝试用OD进行动态调试,并和IDA中的伪C代码作比较
3. OD 动态调试
一句一句分析理解,直接上代码和注释了
3.1 loc_404600函数
输入“abcdefghijklmnopqrstuvwxyz123456”作为测试,第56行找到了loc_404600函数,进入
push ebp
8BEC mov ebp,esp
6A FF push -0x1
735F4000 push test.00405F73
0040460A :A1 mov eax,dword ptr fs:[]
push eax ; eax=0x19FF1C
: >mov dword ptr fs:[],esp
81EC B0000000 sub esp,0xB0 ; 为局部变量申请栈空间
0040461E C745 EC >mov dword ptr ss:[ebp-0x14],0x0 ; 原本指向flag前16个字符
FB614000 push test.004061FB ; 指向开头的字符串--360CTF...
0040462A 8D4D 8C lea ecx,dword ptr ss:[ebp-0x74]
0040462D E8 5ED8FFFF call test.00401E90
C745 FC >mov dword ptr ss:[ebp-0x4],0x0
push test.
0040463E 8D4D A4 lea ecx,dword ptr ss:[ebp-0x5C] ; 0x19fe60其中的值为0x0F
E8 4AD8FFFF call test.00401E90
C645 FC mov byte ptr ss:[ebp-0x4],0x1 ; 下面的字符串压入了0x19FE00=EBP-0xC0
0040464A push test. ; ASCII "12345679"
0040464F 8D8D 74FFFFFF lea ecx,dword ptr ss:[ebp-0x8C]
E8 36D8FFFF call test.00401E90 ; 返回的eax="123456789"
0040465A C645 FC mov byte ptr ss:[ebp-0x4],0x2
0040465E C745 E8 6C62400>mov dword ptr ss:[ebp-0x18],test.>; ASCII "greatctf"
8D4D F3 lea ecx,dword ptr ss:[ebp-0xD]
E8 F3D6FFFF call test.00401D60
0040466D C645 FC mov byte ptr ss:[ebp-0x4],0x3
8B45 E8 mov eax,dword ptr ss:[ebp-0x18]
push eax ; 将新赋值的eax="greatctf"压入栈中
E8 call <jmp.&api-ms-win-crt-string-l1--.>; 计算长度strlen
0040467A 83C4 add esp,0x4
0040467D 8BC8 mov ecx,eax ; ecx=8
0040467F 8B45 EC mov eax,dword ptr ss:[ebp-0x14] ; eax=[ebp-0x14]
33D2 xor edx,edx ; edx清零
F7F1 div ecx ; [ebp-0x14]/8
8B45 E8 mov eax,dword ptr ss:[ebp-0x18] ; eax="greatctf"
0FBE0C10 movsx ecx,byte ptr ds:[eax+edx] ; 取eax=“greatctf”的第edx(这里相当于是[ebp-0x14]%8的值)个字节放入ecx
0040468D 8B55 mov edx,dword ptr ss:[ebp+0x8] ; edx="abcdefghijklmnop",flag前16个字符
EC add edx,dword ptr ss:[ebp-0x14] ; edx=edx+0
0FBE02 movsx eax,byte ptr ds:[edx] ; 取edx="abc..."的第edx([ebp-0x14])个字节放入eax
33C1 xor eax,ecx ; “greatctf"的首字母与"abcd.."的首字母做异或
8B4D mov ecx,dword ptr ss:[ebp+0x8] ; ecx="abcdefghijklmnop"的地址
0040469B 034D EC add ecx,dword ptr ss:[ebp-0x14] ; ecx=ecx+0---有点怀疑是个循环操作了
0040469E mov byte ptr ds:[ecx],al ; 将异或结果保存到"abcd..."的首字符处
004046A0 8B55 EC mov edx,dword ptr ss:[ebp-0x14] ; edx=0
004046A3 83C2 add edx,0x1 ; edx=edx+1
004046A6 EC mov dword ptr ss:[ebp-0x14],edx ; 更新[ebp-0x14]中的值为edx
004046A9 8B45 EC mov eax,dword ptr ss:[ebp-0x14] ; 将[ebp-0x14]赋值到eax
004046AC 3B45 0C cmp eax,dword ptr ss:[ebp+0xC] ; eax与16比较,截取的部分flag的长度
004046AF ^ 7C C0 jl Xtest. ; 小于就跳回上面,继续执行异或操作
004046B1 83EC sub esp,0x18 ; 获取大小为0x18的栈空间
004046B4 8BCC mov ecx,esp
004046B6 D0 mov dword ptr ss:[ebp-0x30],esp ; 将esp=0x19FDEC存入0x19FE90
004046B9 8B55 mov edx,dword ptr ss:[ebp+0x8] ; 将0x19fefc存入edx
004046BC push edx ; edx入栈,0x19fde8,[ebp-d8],edx的地址指向的值是异或后的结果
004046BD E8 CED7FFFF call test.00401E90
004046C2 CC mov dword ptr ss:[ebp-0x34],eax ; eax=0x19FDEC,即异或后的地址存入0x19FE8C
004046C5 C645 FC mov byte ptr ss:[ebp-0x4],0x4 ; 0x4存入0x19febc
004046C9 6A 2A push 0x2A ; 将0x2a压入栈中
004046CB 83EC sub esp,0x18 ; esp=0x19fdd0
004046CE 8BCC mov ecx,esp
004046D0 C8 mov dword ptr ss:[ebp-0x38],esp
004046D3 8B45 mov eax,dword ptr ss:[ebp+0x8]
004046D6 push eax ; eax=0x19fefc
004046D7 E8 B4D7FFFF call test.00401E90
004046DC 8D8D 5CFFFFFF lea ecx,dword ptr ss:[ebp-0xA4] ; ecx=0x19fe1c
004046E2 push ecx
004046E3 C645 FC mov byte ptr ss:[ebp-0x4],0x3 ; 0x3存入0x19febc
004046E7 8D4D F3 lea ecx,dword ptr ss:[ebp-0xD] ; ecx=0x19feb3
004046EA E8 51F0FFFF call test. ; 自身平方
004046EF E4 mov dword ptr ss:[ebp-0x1C],eax ; eax=0x19fe1c
004046F2 8B55 E4 mov edx,dword ptr ss:[ebp-0x1C] ; edx=0x19fe1c
004046F5 E0 mov dword ptr ss:[ebp-0x20],edx
004046F8 8B45 E0 mov eax,dword ptr ss:[ebp-0x20] ; eax=0x19fe1c
004046FB push eax
004046FC 8D4D 8C lea ecx,dword ptr ss:[ebp-0x74] ; ecx=0x19fe4c
004046FF E8 0CD9FFFF call test.
8D8D 5CFFFFFF lea ecx,dword ptr ss:[ebp-0xA4] ; ecx=0x19fe1c
0040470A E8 C1D8FFFF call test.00401FD0
0040470F 83EC sub esp,0x18 ; esp=0x19fdec
8BCC mov ecx,esp
C4 mov dword ptr ss:[ebp-0x3C],esp ; [0x19fe84]=0x19fdec
8D95 74FFFFFF lea edx,dword ptr ss:[ebp-0x8C] ; edx="12345679"的地址0x19fe34
0040471D push edx ; edx入栈
0040471E E8 CDD6FFFF call test.00401DF0
C0 mov dword ptr ss:[ebp-0x40],eax ; eax为"12345679"的地址,赋值到[0x19fe80]
C645 FC mov byte ptr ss:[ebp-0x4],0x5 ; [0x19febc]=0x5
0040472A 6A 2A push 0x2A ; 2a入栈
0040472C 83EC sub esp,0x18
0040472F 8BCC mov ecx,esp
BC mov dword ptr ss:[ebp-0x44],esp ; [0x19fe7c]=0x19fdd0
8D45 8C lea eax,dword ptr ss:[ebp-0x74] ; 取")*0990510578848262884380342813696"的地址0x19fe4c存入eax
push eax
E8 B3D6FFFF call test.00401DF0
0040473D 8D8D 44FFFFFF lea ecx,dword ptr ss:[ebp-0xBC] ; ecx=0x19fe04
push ecx
C645 FC mov byte ptr ss:[ebp-0x4],0x3 ; [0x19febc]=0x3
8D4D F3 lea ecx,dword ptr ss:[ebp-0xD] ; ecx=0x19feb3
0040474B E8 F0EFFFFF call test. ; 与123456789相乘
DC mov dword ptr ss:[ebp-0x24],eax ; "'-+4823339700468499618579595434614979584"的地址eax=0x19fe04
8B55 DC mov edx,dword ptr ss:[ebp-0x24] ; edx=0x19fe04
D8 mov dword ptr ss:[ebp-0x28],edx ; [0x19fe98]=0x19fe04
8B45 D8 mov eax,dword ptr ss:[ebp-0x28] ; eax=0x19fe04
0040475C push eax ; eax入栈
0040475D 8D4D A4 lea ecx,dword ptr ss:[ebp-0x5C] ; ecx=0x19fe64
E8 ABD8FFFF call test.
8D8D 44FFFFFF lea ecx,dword ptr ss:[ebp-0xBC] ; ecx=0x19fe04
0040476B E8 60D8FFFF call test.00401FD0
8D4D A4 lea ecx,dword ptr ss:[ebp-0x5C] ; ecx=0x19fe64
E8 48FEFFFF call test.004045C0
D4 mov dword ptr ss:[ebp-0x2C],eax ; 将"'-+4823339700468499618579595434614979584"的地址0x5d68d0存入0x19fe94
0040477B 8B4D D4 mov ecx,dword ptr ss:[ebp-0x2C] ; ecx=0x19fe94
0040477E push ecx ; s2="'-+4823339700468499618579595434614979584"
0040477F push test. ; s1="667339003789000121539302795007135856775"地址入栈
E8 0B150000 call <jmp.&api-ms-win-crt-string-l1--.>; strcmp
83C4 add esp,0x8
0040478C 85C0 test eax,eax
0040478E jnz Xtest.004047D1
地址004046EA ,调用test.00403740,进入之后可以找到一段平方的代码
0040287B 8B55 F0 mov edx,dword ptr ss:[ebp-0x10] ; 循环跳转位置
0040287E 83EA sub edx,0x1
F0 mov dword ptr ss:[ebp-0x10],edx
837D F0 cmp dword ptr ss:[ebp-0x10],0x0
0F8C jl test. ; 循环结束条件
0040288E 8B45 F0 mov eax,dword ptr ss:[ebp-0x10]
push eax
8D4D 0C lea ecx,dword ptr ss:[ebp+0xC]
E8 16F8FFFF call test.004020B0
0040289A 0FBE08 movsx ecx,byte ptr ds:[eax] ; 将低位的一字节移动到ecx
0040289D 83E9 sub ecx,0x30
004028A0 8BC1 mov eax,ecx
004028A2 0FAF45 E0 imul eax,dword ptr ss:[ebp-0x20]
004028A6 E8 add eax,dword ptr ss:[ebp-0x18]
004028A9 cdq
004028AA B9 0A000000 mov ecx,0xA
004028AF F7F9 idiv ecx
004028B1 D8 mov dword ptr ss:[ebp-0x28],edx
004028B4 8B55 F0 mov edx,dword ptr ss:[ebp-0x10]
004028B7 push edx
004028B8 8D4D 0C lea ecx,dword ptr ss:[ebp+0xC]
004028BB E8 F0F7FFFF call test.004020B0
004028C0 0FBE00 movsx eax,byte ptr ds:[eax] ; 将低位的一字节移动到eax
004028C3 83E8 sub eax,0x30 ; 将字符转换为整型数据
004028C6 0FAF45 E0 imul eax,dword ptr ss:[ebp-0x20] ; 从低位开始一位一位的自身相乘
004028CA E8 add eax,dword ptr ss:[ebp-0x18]
004028CD cdq
004028CE B9 0A000000 mov ecx,0xA
004028D3 F7F9 idiv ecx
004028D5 E8 mov dword ptr ss:[ebp-0x18],eax
004028D8 8D55 lea edx,dword ptr ss:[ebp-0x7C]
004028DB push edx
004028DC 8B45 D8 mov eax,dword ptr ss:[ebp-0x28]
004028DF 83C0 add eax,0x30 ; 整型转换为字符
004028E2 push eax
004028E3 8D8D 48FFFFFF lea ecx,dword ptr ss:[ebp-0xB8]
004028E9 push ecx
004028EA E8 01E8FFFF call test.004010F0
004028EF 83C4 0C add esp,0xC
004028F2 C8 mov dword ptr ss:[ebp-0x38],eax
004028F5 8B55 C8 mov edx,dword ptr ss:[ebp-0x38]
004028F8 push edx
004028F9 8D4D lea ecx,dword ptr ss:[ebp-0x7C]
004028FC E8 0FF7FFFF call test.
8D8D 48FFFFFF lea ecx,dword ptr ss:[ebp-0xB8]
E8 C4F6FFFF call test.00401FD0
0040290C ^ E9 6AFFFFFF jmp test.0040287B ; 进行下一个循环
同样的,第97行代码,对字符串乘12345679也是一样
3.2 处理总结
在第109行~第113行代码,这就是一个将输入字符串前16个字符处理之后(先异或"greatctf",再自身平方,最后乘以12345679),与"667339003789000121539302795007135856775"比较。
因此,我们只需要逆向处理,就能得到输入字符的前16个字符
4.脚本处理
str1 = "greatctf"
num2 = 667339003789000121539302795007135856775
flag="" num2 = num2 // 12345679
num2 = pow(num2, 0.5)
str2 = str(num2) for i in range(16):
flag += chr(ord(str2[i]) ^ ord(str1[i%8]))
print(flag)
得到前16个字符
PAPSETGQ_FRRBQLS
5. sub_404860函数
v33 = &v21;
v32 = (int *)&v25;
v31 = (int *)&v23;
v30 = &v22;
v21 = *a1;
v25 = a1[];
v26 = ;
v23 = a1[];
v24 = ;
LOWORD(v22) = *((_WORD *)a1 + );
BYTE2(v22) = *((_BYTE *)a1 + );
*(_DWORD *)((char *)&v22 + ) = *((unsigned __int8 *)a1 + );
HIBYTE(v22) = ;
srand(0xBC6146u);
v29 = rand() % ;
v20 = rand() % ;
v27 = rand() % ;
v28 = rand() % ;
v1 = sub_404FC0(v25, v26, , );
v3 = v2;
LODWORD(v4) = sub_404FC0(v29, HIDWORD(v29), , );
if ( v21 + __PAIR__(v3, v1) - v4 != 0x1A06491E7i64 )
goto LABEL_9;
v5 = sub_404FC0(v27, HIDWORD(v27), v23, v24);
v7 = v6;
LODWORD(v8) = sub_404FC0(v25, v26, v20, HIDWORD(v20));
if ( __PAIR__(v7, v5) - v8 != 0x244BFD2B9Ci64
|| (v9 = sub_404FC0(v23, v24, v28, HIDWORD(v28)),
v11 = v10,
LODWORD(v12) = sub_404FC0(v22 + , (unsigned __int64)(v22 + ) >> , v29, HIDWORD(v29)),
v12 + __PAIR__(v11, v9) != 0x71CE119D5i64)
|| (v13 = sub_404FC0(v28, HIDWORD(v28), , ),
v15 = sub_404FC0(v13, v14, v22, HIDWORD(v22)),
v17 = v16,
LODWORD(v18) = sub_404FC0(v27, HIDWORD(v27), v21, HIDWORD(v21)),
__PAIR__(v17, v15) - v18 != 0x431E9A36840i64) )
{
LABEL_9:
result = ;
}
else
{
result = ;
}
return result;
}
5.1 代码分析
第14行代码~第18行代码,在生成随机数,这些数在后面也会用到,因此可以写一个生成随机数的程序。
#include <bits/stdc++.h> using namespace std; int main(){
int v15,v8,v14,v13; srand(0xbc6146);
v15 = rand() % ;
v8 = rand() % ;
v13 = rand() % ;
v14 = rand() % ; cout << v15 << " " << v8 << " " << v13 << " " << v14 << endl; return ;
}
输出
2 11 192 31
又因为这个函数要返回1,使得上一层的判断成立,因此我们要让27~36行代码不成立。则,利用z3包,我们能够写出脚本
5.2 脚本获取
引用官方的WP给出的脚本
from z3 import *
import struct
s = [Int('serial%d' % i) for i in range()]
z3 = Solver() v1 =
v2 =
v3 =
v4 = z3.add(*s[]-*v1+s[] == )
z3.add(v3*s[]-s[]*v2 == )
z3.add(s[]*v4+(+s[])*v1 == )
z3.add(v4**s[]-v3*s[] == ) print(z3.check())
answer=z3.model()
res = ""
for d in s:
num = answer.eval(d).as_long()
res += struct.pack('<L', num)
print(repr(res))
得到
simpleRe__360CTF
6.get flag!
两段组合
PAPSETGQ_FRRBQLSsimpleRe__360CTF
参考
2.https://www.cnblogs.com/harmonica11/p/11723241.html
2019 360杯 re wp--Here are some big nums的更多相关文章
- 2019红帽杯部分wp
xx 程序首先取输入的前4个字符作为xxtea加密的密钥之后进行xxtea加密.接着进行位置置换操作,然后又进行了以3个为一组的异或 首先逆向解出xxtea加密之后的结果 #include<st ...
- 2019 红帽杯 Re WP
0x01 xx 测试文件:https://www.lanzous.com/i7dyqhc 1.准备 获取信息 64位文件 2.IDA打开 使用Findcrypt脚本可以看到 结合文件名是xx,因此猜测 ...
- [BUUCTF]REVERSE——[2019红帽杯]easyRE
[2019红帽杯]easyRE 附件 步骤: ida载入,没有main函数,就先检索了程序里的字符串 发现了base64加密的特征字符串,双击you found me跟进,找到了调用它的函数,函数很长 ...
- 第二届360杯全国大学生信息安全技术大赛部分解题思路(WEB安全)
第一题如下: 用burpsuit设置好代理后,点击发送验证码,可以看到如下: 然后go之后可以看到如下的验证码: 提交验证码后即可获得key 第二题如下: 通过/data/mysql_error_tr ...
- 2019 湖湘杯 Reverse WP
0x01 arguement 下载链接:https://www.lanzous.com/i7atyhc 1.准备 获取到信息: 32位的文件 upx加密文件 在控制台打开文件 使用"upx ...
- 2019"深思杯"山东省大学生网络安全技能大赛部分wp
签到 载入OD查看字符串 上下左右 这道题出来的时候真的是一点思路都没有,一直以为是什么编码来着,看了大佬们的 wp 原来是画图 拿大佬的脚本: from PIL import Image im = ...
- 2019强网杯babybank wp及浅析
前言 2019强网杯CTF智能合约题目--babybank wp及浅析 ps:本文最先写在我的新博客上,后面会以新博客为主,看心情会把文章同步过来 分析 反编译 使用OnlineSolidityDec ...
- 记 2019蓝桥杯校内预选赛(JAVA组) 赛后总结
引言 好像博客好久没更新了 哈哈哈哈哈 趁现在有空更新一波 不知道还有没有人看 确实该记录一下每天做了什么了 不然感觉有些浑浑噩噩了 比赛介绍 全称: 蓝桥杯全国软件和信息技术专业人才大赛 蓝桥杯 实 ...
- 2019 蓝桥杯省赛 A 组模拟赛(一)-修建公路
题目: 蒜头国有 nn 座城市,编号分别为 0,1,2,3,...,n-1.编号为 x 和 y 的两座城市之间如果要修高速公路,必须花费 x|y 个金币,其中|表示二进制按位或. 吝啬的国王想要花最少 ...
随机推荐
- zookeeper3.5.5集群部署
ZooKeeper是一个为分布式应用所设计的分布的.开源的协调服务,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,简化分布式应用协调及其管理的难度,提供高性能的分布式服务.ZooKeeper ...
- Java 内置锁 重入问题
阅读<Java并发编程实战>,遇到了一个问题 代码如下 /** * @auther draymonder */ public class Widget { public synchroni ...
- HDU 6191 Query on A Tree(字典树+离线)
Query on A Tree Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Othe ...
- Httpwatch抓包
一.下载Httpwatch 二.抓包 1.启动Httpwatch 打开浏览器-选择工具-Httpwatch professional(仅适用于IE和火狐40及以下浏览器) 2.开始抓包 点击“Reco ...
- Vuex入门(转)
参考:https://segmentfault.com/a/1190000015782272 https://www.cnblogs.com/y896926473/p/6709733.html 如果你 ...
- spring cloud:HystrixDashboard
hystrix-dashboard-server 1. File-->new spring starter project 2.add dependency <parent> < ...
- event.currentTarget
https://api.jquery.com/event.currentTarget/ event.currentTargetReturns: Element Description: The cur ...
- java 栈和栈帧
文章转载自:http://www.tuicool.com/articles/URZrMnb jvm为每个新创建的线程都分配一个堆栈.堆栈以帧为单位保存线程的状态.jvm对堆栈只进行两种操作:以帧为单位 ...
- sklearn—支持向量机
SVC介绍: 拟合出来的模型为一个超平面 解决与样本维数无关,适合做文本分类 解决小样本.非线性.高维 是用于分类.回归.孤立点检测的监督学习方法的集合. 优点: 有效的高维空间 维数大于样本数的时候 ...
- 阶段3 1.Mybatis_08.动态SQL_01.mybatis中的动态sql语句-if标签
创建新的工程 复制到新建的项目里面 pom.xml依赖部分复制过来 dao中整理代码 只保留四个查询 映射文件也只保留四个查询方法 增加一个根据条件查询的方法. 由于用了别名,所以parpameter ...