前言
给同学写个小程序,测试给定的rdp ip,port, user,pwd,是否为正确的登录信息。
开始他找了个基于x11的开源程序(还是个服务程序, 不能直接看到rdp登录的效果),让我抽出rdp登录的实现,做个工程。
看了一下,牵扯的还挺多,最重要的是编译不过(开源的工程各种依赖),无法看到实际运行的效果。如果要研究编译过,工作流程的实现,需要时间。如果要从他找的x11开源程序中抽取出rdp登录的实现,这周末时间也不够啊:)
对于这种友情任务,非正式的工程,抓到老鼠,就是好猫。谁会关心是咋实现的:)
我去找了freerdp,编译完,可以运行。看了登录那块,还不是在最开始就登录(开始就是去连接一下,只能确定ip, port是否正确)。也是各种类嵌套的很紧。freerdp是可以调试,也能追到登录那。不过,要想抽取出来,不带x11, 时间上也不允许。
我换了个思路在想这事。同学要的就是rdp登录验证,网上有很多协议登录暴力破解的程序。和登录验证不同之处,就是暴力破解程序不知道登录信息中的user/pwd, 我这场景知道user/pwd. 就这点区别。我找个暴力破解登录信息的程序,改一下,只登录一次,知道登录成功/失败即可。
按照这个思路,我找到了ncrack, 研究了一天(命令行的使用,登录成功和失败的实现在哪里),发现ncrack有个bug, 如果给出的是错误的用户名和口令,ncrack不退出。我将这bug修复了。按照ncrack的使用场景,这不算是bug(本来就要登录不成功,就要换登录信息重试的)。
改完之后的效果:在ncrack命令行给定rdp登录信息(ip, port, user, pwd)和日志名称, 登录一次,不管登录成功或失败,都要退出。然后看日志,如果日志中出现"Discovered credentials on rdp",说明找到了rdp登录的凭据有效,否则为登录失败。
后续我再写个小程序来调用改版的ncrack, 等ncrack执行完,去查日志,找登录成功或失败的字符串标记,如果成功,程序退出码为EXIT_SUCCESS;如果失败,程序退出码为其他值。这样,就完成了验证rdp登录信息是否正确的任务。
实验
本实验目的:ncrack的下载,编译,修改,验证单次登录。
ncrack的下载
github上有ncrack的master分支,这个分支编译不过的。要去下载ncrack的发布版本.
https://nmap.org/ncrack/dist/ncrack-0.6.tar.gz
如果要想学习其他发布版本,去https://nmap.org/ncrack/dist/可以看到
编译环境
正好换了硬盘,重新装了一个debian8.8的虚拟机环境。刚装完,就做了一个快照,就从这个快照开始做实验。
su - root
mkdir /home/dev
chmod 777 -R /home/dev
cd /home/dev
下载ncrack
wget https://nmap.org/ncrack/dist/ncrack-0.6.tar.gz
ls -l
总用量 3824
-rw-r--r-- 1 root root 3913259 10月 30 2017 ncrack-0.6.tar.gz
root@debian8-8-bits64:/home/dev# tar -xzvf ./ncrack-0.6.tar.gz
ls -l
总用量 3828
drwxrwxr-x 10 root root 4096 10月 12 2017 ncrack-0.6.0
-rw-r--r-- 1 root root 3913259 10月 30 2017 ncrack-0.6.tar.gz
cd ncrack-0.6.0/
修改软件源
cat /etc/apt/sources.list
#
# deb cdrom:[Debian GNU/Linux 8.8.0 _Jessie_ - Official amd64 DVD Binary-1 20170506-14:13]/ jessie contrib main
# deb cdrom:[Debian GNU/Linux 8.8.0 _Jessie_ - Official amd64 DVD Binary-1 20170506-14:13]/ jessie contrib main
deb http://mirrors.163.com/debian/ jessie main
deb-src http://mirrors.163.com/debian/ jessie main
deb http://security.debian.org/ jessie/updates main contrib
deb-src http://security.debian.org/ jessie/updates main contrib
# jessie-updates, previously known as 'volatile'
deb http://mirrors.163.com/debian/ jessie-updates main contrib
deb-src http://mirrors.163.com/debian/ jessie-updates main contrib
更新软件源
aptitude update
安装依赖环境
aptitude install build-essential checkinstall libssl-dev libssh-dev
aptitude install autoconf
编译ncrack
./configure
这个配置是release版,如果要调试程序,需要自己将每个Makefile中去掉 -O2选项,加上-g选项
用find先将所有的Makefile都找出来
find . -name 'Makefile'
./modules/Makefile
./mswin32/Makefile
./macosx/Makefile
./opensshlib/Makefile
./Makefile
./nsock/examples/Makefile
./nsock/src/Makefile
./nsock/tests/Makefile
./nbase/Makefile
./docs/Makefile
拿主Makefile来做例子,看看要改哪里。如果不改,用gdb调试时,看不到源码。
每次执行./configure后,都会覆盖所有的Makefile.
将所有的Makefile都修改成debug版之后,make clean 后,删除*.log, 用winscp传回本地svn目录存档,如果在同一个环境下编译工程,以后就不需要再执行./configure. 只需要改代码,上传,编译.
为了winscp能上传覆盖/home/dev/ncrack-0.6.0(编译的时候用的root用户,winscp是其他用户),需要修改/home/dev/ncrack-0.6.0的权限。
chmod 777 -R /home/dev
将改过Makefile的工程上传后,编译一下
make
不用安装了,直接运行程序就行。
命令行参数列表
root@debian8-8-bits64:/home/dev/ncrack-0.6.0# ./ncrack --help
Ncrack 0.6 ( http://ncrack.org )
Usage: ncrack [Options] {target and service specification}
TARGET SPECIFICATION:
Can pass hostnames, IP addresses, networks, etc.
Ex: scanme.nmap.org, microsoft.com/24, 192.168.0.1; 10.0.0-255.1-254
-iX <inputfilename>: Input from Nmap's -oX XML output format
-iN <inputfilename>: Input from Nmap's -oN Normal output format
-iL <inputfilename>: Input from list of hosts/networks
--exclude <host1[,host2][,host3],...>: Exclude hosts/networks
--excludefile <exclude_file>: Exclude list from file
SERVICE SPECIFICATION:
Can pass target specific services in <service>://target (standard) notation or
using -p which will be applied to all hosts in non-standard notation.
Service arguments can be specified to be host-specific, type of service-specific
(-m) or global (-g). Ex: ssh://10.0.0.10,at=10,cl=30 -m ssh:at=50 -g cd=3000
Ex2: ncrack -p ssh,ftp:3500,25 10.0.0.10 scanme.nmap.org google.com:80,ssl
-p <service-list>: services will be applied to all non-standard notation hosts
-m <service>:<options>: options will be applied to all services of this type
-g <options>: options will be applied to every service globally
Misc options:
ssl: enable SSL over this service
path <name>: used in modules like HTTP ('=' needs escaping if used)
db <name>: used in modules like MongoDB to specify the database
domain <name>: used in modules like WinRM to specify the domain
TIMING AND PERFORMANCE:
Options which take <time> are in seconds, unless you append 'ms'
(miliseconds), 'm' (minutes), or 'h' (hours) to the value (e.g. 30m).
Service-specific options:
cl (min connection limit): minimum number of concurrent parallel connections
CL (max connection limit): maximum number of concurrent parallel connections
at (authentication tries): authentication attempts per connection
cd (connection delay): delay <time> between each connection initiation
cr (connection retries): caps number of service connection attempts
to (time-out): maximum cracking <time> for service, regardless of success so far
-T<0-5>: Set timing template (higher is faster)
--connection-limit <number>: threshold for total concurrent connections
--stealthy-linear: try credentials using only one connection against each specified host
until you hit the same host again. Overrides all other timing options.
AUTHENTICATION:
-U <filename>: username file
-P <filename>: password file
--user <username_list>: comma-separated username list
--pass <password_list>: comma-separated password list
--passwords-first: Iterate password list for each username. Default is opposite.
--pairwise: Choose usernames and passwords in pairs.
OUTPUT:
-oN/-oX <file>: Output scan in normal and XML format, respectively, to the given filename.
-oA <basename>: Output in the two major formats at once
-v: Increase verbosity level (use twice or more for greater effect)
-d[level]: Set or increase debugging level (Up to 10 is meaningful)
--nsock-trace <level>: Set nsock trace level (Valid range: 0 - 10)
--log-errors: Log errors/warnings to the normal-format output file
--append-output: Append to rather than clobber specified output files
MISC:
--resume <file>: Continue previously saved session
--save <file>: Save restoration file with specific filename
-f: quit cracking service after one found credential
-6: Enable IPv6 cracking
-sL or --list: only list hosts and services
--datadir <dirname>: Specify custom Ncrack data file location
--proxy <type://proxy:port>: Make connections via socks4, 4a, http.
-V: Print version number
-h: Print this help summary page.
MODULES:
SSH, RDP, FTP, Telnet, HTTP(S), POP3(S), IMAP, SMB, VNC, SIP, Redis, PostgreSQL, MySQL, MSSQL, MongoDB, Cassandra, WinRM, OWA
EXAMPLES:
ncrack -v --user root localhost:22
ncrack -v -T5 https://192.168.0.1
ncrack -v -iX ~/nmap.xml -g CL=5,to=1h
SEE THE MAN PAGE (http://nmap.org/ncrack/man.html) FOR MORE OPTIONS AND EXAMPLES
选择合适的命令行参数做测试
命令行参数应该包括ip, port, user,pwd, 超时时间,日志名称
输入正确的参数后,应该能登录rdp服务器才对。
/home/dev/ncrack-0.6.0/ncrack -oN /home/dev/scan.log --user administrator --pass 111111 rdp://192.168.2.61:3389,to=3
上述命令行参数的含义
-oN 指定日志名称
--user 指定用户名
--pass 指定口令
rdp://192.168.2.61:3389 指定协议为rdp, ip和port
to=3 指定单次登录超时时间,过了这个超时时间,本次登录就放弃。
值得注意的是to参数必须跟在ip,port之后,前面有‘,’符号
看ncrack的--help说明中的例子,可以看出如果是-x参数, 就可以写在前面。如果不带-的参数,就必须写在ip,port的后面
如果能编译过了,能正常运行,就可以用si建立看代码的工程,用gdb去调试,看看程序的实现思路和细节。
如果测试出bug,先看看命令行参数是否指定的不合适(因为不是自己写的程序,有可能命令行参数组合的复杂,暂时指定的不对,或真的没有参数符合自己的应用),如果真的不是命令行指定的错误或者真的不符合自己的应用,这时才需要去改工程。
写个脚本来测试编译出的ncrack
写个脚本可以使测试的更方便,还可以在脚本中记录笔记.
#!/bin/sh
# @file rdp_test.sh
# @brief test how to use ncrack to test rdp protocol connect
fn_print_empty_line() {
# $1 is parameter 1
for i in $(seq 1 1 $1)
do
echo
done
return 0
}
fn_test_ncrack() {
# 不好使
# config project to debug version
# ./configure --enable-debug
# ok
# /home/dev/ncrack-0.6.0/ncrack --help > /home/dev/ncrack.help
# cat /home/dev/ncrack.help
# /home/dev/ncrack-0.6.0/ncrack -T1 -vv -d10 -oN /home/dev/scan.log --user administrator --pass 111111 192.168.2.61:3389 >& /home/dev/run_result.log
# /home/dev/ncrack-0.6.0/ncrack -T1 -vv -d10 -oN /home/dev/scan.log --user administrator --pass 111111 192.168.2.61:3389 > /home/dev/run_result.log
# /home/dev/ncrack-0.6.0/ncrack --help > /home/dev/run_result.log
# /home/dev/ncrack-0.6.0/ncrack -T1 -vv -d10 -oN /home/dev/scan.log --user administrator --pass 111111 rdp://192.168.2.61:3389 > /home/dev/run_result.log
# 不能重定向到文件, 会有报错: Text: irrelevant message
# /home/dev/ncrack-0.6.0/ncrack -T1 -vv -d10 -oN /home/dev/scan.log --user administrator --pass 111111 rdp://192.168.2.61:3389 > /home/dev/run_result.log
# ok
# /home/dev/ncrack-0.6.0/ncrack -T1 -vv -d10 -oN /home/dev/scan.log --user administrator --pass 111111 rdp://192.168.2.61:3389
# ok
# /home/dev/ncrack-0.6.0/ncrack -T1 -vv -d10 -oN /home/dev/scan.log --user administrator --pass 111111 rdp://192.168.2.61:3389,at=0,cl=1
# ok
# /home/dev/ncrack-0.6.0/ncrack -vv -d10 -oN /home/dev/scan.log --user administrator --pass 111111 rdp://192.168.2.61:3389,to=3
# ok 这是信息输出最少的命令行参数
/home/dev/ncrack-0.6.0/ncrack -oN /home/dev/scan.log --user administrator --pass 111111 rdp://192.168.2.61:3389,to=3
# fn_print_empty_line 6
# cat /home/dev/run_result.log
fn_print_empty_line 6
# 在 /home/dev/scan.log 中找字符串 "Discovered credentials on rdp"
# 如果找到, 说明登录成功
cat /home/dev/scan.log
return 0
}
main() {
# clear screen
clear
# print 25 empty lines
fn_print_empty_line 25
# test ncrack
fn_test_ncrack
}
main
exit 0
chmod 777 /home/dev/*.sh
/home/dev/rdp_test.sh
根据单次登录的场景修改代码
测试的结果为:
- 如果工程未修改,给的登录参数对,程序执行完,就退出,并生成日志
- 如果工程未修改,给的登录参数不对,程序运行起来,始终不会退出。
加了-vv -d10参数,发现了工程实现中有死循环的地方。作者的调试思路真细致。
用gdb单步,看看在哪改合适
/home/dev/ncrack-0.6.0# chmod 777 -R ./*
将自己改过Makefile为-g的版本上传, 然后再make一次, 不要运行./configure
aptitude install gdb
gdb -tui --args /home/dev/ncrack-0.6.0/ncrack -vv -d10 -oN /home/dev/scan.log --user administrator --pass 111111 rdp://192.168.2.61:3389,to=3
通过日志信息和单步的结果,看到应该改/ncrack-0.6.0/ncrack.cc中的ncrack(ServiceGroup *SG),
针对我的场景(正规登录一次),改这里好使。
static int
ncrack(ServiceGroup *SG)
{
bool is_process_continue = true; // 是否继续处理
/* nsock variables */
struct timeval now;
enum nsock_loopstatus loopret;
list <Service *>::iterator li;
nsock_pool nsp;
int nsock_timeout = 3000;
int err;
/* create nsock p00l */
if (!(nsp = nsock_pool_new(SG)))
fatal("Can't create nsock pool.");
if (o.proxychain) {
if (nsock_pool_set_proxychain(nsp, o.proxychain) == -1)
fatal("Unable to set proxychain for nsock pool");
}
gettimeofday(&now, NULL);
nsock_set_loglevel(o.nsock_loglevel);
#if HAVE_OPENSSL
/* We don't care about connection security, so cast Haste */
nsock_pool_ssl_init(nsp, NSOCK_SSL_MAX_SPEED);
#endif
SG->findMinDelay();
/* We have to set the nsock_loop timeout to the minimum of the connection
* delay, since we have to check every that time period for potential new
* connection initiations. If the minimum connection delay is 0 however, we
* don't need to do it, since that would make nsock_loop return immediately
* and consume a lot of CPU.
*/
if (SG->min_connection_delay != 0)
nsock_timeout = SG->min_connection_delay;
/* Initiate time-out clocks */
startTimeOutClocks(SG);
/* initiate all authentication rate meters */
SG->auth_rate_meter.start();
for (li = SG->services_all.begin(); li != SG->services_all.end(); li++)
(*li)->auth_rate_meter.start();
/*
* Since nsock can delay between each event due to the targets being really
* slow, we need a way to make sure that we always poll for interactive user
* input regardless of the above case. Thus we schedule a special timer event
* that happens every KEYPRESSED_INTERVAL milliseconds and which reschedules
* itself every time its handler is called.
*/
nsock_timer_create(nsp, status_timer_handler, KEYPRESSED_INTERVAL, NULL);
/*
* We do the same for checking pending signals every SIGNAL_CHECK_INTERVAL
*/
nsock_timer_create(nsp, signal_timer_handler, SIGNAL_CHECK_INTERVAL, NULL);
ncrack_probes(nsp, SG);
/* nsock loop */
do {
loopret = nsock_loop(nsp, nsock_timeout);
switch (loopret) {
case NSOCK_LOOP_TIMEOUT: {
is_process_continue = false;
err = nsock_pool_get_error(nsp);
error("nsock_loop timeout : Error code %d (%s)",
err, strerror(err));
}
break;
case NSOCK_LOOP_ERROR: {
is_process_continue = false;
err = nsock_pool_get_error(nsp);
error("nsock_loop error : Unexpected, Error code %d (%s)",
err, strerror(err));
}
break;
case NSOCK_LOOP_QUIT: {
is_process_continue = false;
err = nsock_pool_get_error(nsp);
error("nsock_loop quit : Error code %d (%s)",
err, strerror(err));
}
break;
default: {
err = nsock_pool_get_error(nsp);
error("nsock_loop unknow return code(%d) : Error code %d (%s)",
(int)loopret,
err, strerror(err));
}
break;
}
ncrack_probes(nsp, SG);
// 如果nsock_loop返回结果是(超时,错误,退出),就不尝试登录了
// 但是也不能强行exit, 按照正常流程走
if (!is_process_continue) {
break;
}
// if task was not finished, continue
} while (SG->services_finished.size() != SG->total_services);
nsock_pool_delete(nsp);
if (o.debugging > 4)
log_write(LOG_STDOUT, "nsock_loop returned %d\n", loopret);
return 0;
}
修改后的效果
不管登录是否成功,拿登录参数去登录都只登录一次,就退出。
然后看日志中是否有登录成功的信息"Discovered credentials on rdp", 如果找到,说明登录成功,否则说明登陆失败。
后续的工作
同学跟我说的需求是搞一个程序,给定登录参数在命令行,如果登录成功,程序返回0;如果登录失败,程序返回错误码。
ncrack实验成功后,那我需要再写个小程序,按照命令行给定的登录参数来拼装调用ncrack的命令行(登录信息,超时时间,日志名称),尝试将屏幕信息都屏蔽掉(e.g. > /dev/null)。在ncrack阻塞执行完成后,去读取指定的ncrack日志,看看日志中是否有登录成功的字符串信息。
调用ncrack和分析日志的小程序
分2个程序,一个C程序干活(调用ncrack+分析日志),一个bash脚本来调用C程序的ELF文件来测试。
测试过了好使
// @file main.cpp
// @brief call ncrack modify version by me, and parse the log file gen by ncrack, to besure login ok or failed
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#include <limits.h>
#include <libgen.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string>
#ifndef MYLOG_D
#define MYLOG_D(fmt, ...) \
do { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "LS_LOG", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
} while (0);
#endif // #ifndef MYLOG_D
void init(const char* psz_log_owner_name);
void uninit();
void proc_sig_term(int num);
int fn_test(int argc, char** argv);
std::string get_pathname_from_pid(pid_t i_pid);
std::string get_path_from_pathname(const char* psz_pathname);
bool is_file_exist(const char* psz_file_pathname);
int parse_ncrack_log_file(const char* psz_log_file_pathname);
int main(int argc, char** argv)
{
int i_rc = EXIT_SUCCESS;
char sz_buf[1024] = {'\0'};
#ifdef MAKE_FILE_MACRO__BIN_NAME
sprintf(sz_buf, "%s", MAKE_FILE_MACRO__BIN_NAME);
init(sz_buf);
MYLOG_D("MAKE_FILE_MACRO__BIN_NAME = [%s]", MAKE_FILE_MACRO__BIN_NAME);
#else
init(NULL);
#endif // #ifdef MAKE_FILE_MACRO__BIN_NAME
i_rc = fn_test(argc, argv);
uninit();
MYLOG_D("THE END");
return i_rc;
}
void init(const char* psz_log_owner_name)
{
int i = 0;
// daemon(0, 0);
openlog(((NULL != psz_log_owner_name) ? psz_log_owner_name : "my_syslog"), LOG_NOWAIT | LOG_PID, LOG_LOCAL1);
// clear screen (print 25 empty line)
for (i = 0; i < 25; i++) {
MYLOG_D("");
}
signal(SIGTERM, proc_sig_term);
}
void uninit()
{
closelog();
}
void proc_sig_term(int num)
{
MYLOG_D("SIGTERM = %d, num = %d", SIGTERM, num);
MYLOG_D("maybe can do some clean task before quit");
exit(1);
}
int fn_test(int argc, char** argv)
{
// 本程序被调用格式的命令行格式
// rdp_login_verify -ip 192.168.2.61 -port 3389 -user administrator -pwd 111111
// 实际执行的程序命令行格式
// ./ncrack -oN /home/dev/scan.log --user administrator --pass 111111 rdp://192.168.2.61:3389,to=3
int i_rc = -1;
int i_fn_rc = -1;
int i = 0;
std::string str_my_pathname = "";
std::string str_my_path = "";
std::string str_ncrack_path = "";
std::string str_ip = "";
std::string str_port = "";
std::string str_user = "";
std::string str_pwd = "";
std::string str_log_file_pathname = "";
char sz_cmd_line[0x1000] = {'\0'};
do {
str_my_pathname = get_pathname_from_pid(getpid());
// /home/dev/rdp_login_verify/rdp_login_verify
MYLOG_D("str_my_pathname = %s", str_my_pathname.c_str());
str_my_path = dirname((char*)str_my_pathname.data());
// /home/dev/rdp_login_verify
MYLOG_D("str_my_path = %s", str_my_path.c_str());
str_ncrack_path = str_my_path.c_str();
str_ncrack_path += "/ncrack";
MYLOG_D("str_ncrack_path = %s", str_ncrack_path.c_str());
if (!is_file_exist(str_ncrack_path.c_str())) {
MYLOG_D("%s not exist...", str_ncrack_path.c_str());
break;
}
// rdp_login_verify -ip 192.168.2.61 -port 3389 -user administrator -pwd 111111
if (9 != argc) {
break;
}
for (i = 1; i <=8; i += 2) {
if (0 == strcmp(argv[i], "-ip")) {
str_ip = argv[i + 1];
} else if (0 == strcmp(argv[i], "-port")) {
str_port = argv[i + 1];
} else if (0 == strcmp(argv[i], "-user")) {
str_user = argv[i + 1];
} else if (0 == strcmp(argv[i], "-pwd")) {
str_pwd = argv[i + 1];
}
}
MYLOG_D("rdp connect info = %s:%s %s/%s",
str_ip.c_str(),
str_port.c_str(),
str_user.c_str(),
str_pwd.c_str());
memset(sz_cmd_line, 0, sizeof(sz_cmd_line));
snprintf(sz_cmd_line, sizeof(sz_cmd_line),
"/tmp/rdp_login_scan_%d.log",
getpid());
str_log_file_pathname = sz_cmd_line;
// 拼命令行
// ./ncrack -oN /home/dev/scan.log --user administrator --pass 111111 rdp://192.168.2.61:3389,to=3
memset(sz_cmd_line, 0, sizeof(sz_cmd_line));
snprintf(sz_cmd_line, sizeof(sz_cmd_line),
"%s -oN %s --user %s --pass %s rdp://%s:%s,to=3",
str_ncrack_path.c_str(),
str_log_file_pathname.c_str(),
str_user.c_str(),
str_pwd.c_str(),
str_ip.c_str(),
str_port.c_str());
MYLOG_D("call [%s]", sz_cmd_line);
// 执行命令
i_fn_rc = system(sz_cmd_line);
if (-1 == i_fn_rc) {
MYLOG_D("shell could not be run");
} else {
MYLOG_D("result of running command is %d", WEXITSTATUS(i_fn_rc));
}
// 分析日志文件
i_rc = parse_ncrack_log_file(str_log_file_pathname.c_str());
// 删除日志文件
unlink(str_log_file_pathname.c_str());
} while (0);
MYLOG_D("rdp login %s", (EXIT_SUCCESS == i_rc) ? "ok" : "failed");
return i_rc;
}
int parse_ncrack_log_file(const char* psz_log_file_pathname)
{
int i_rc = EXIT_FAILURE;
FILE* pf = NULL;
char sz_buf[0x1000] = {'\0'};
do {
if (NULL == psz_log_file_pathname) {
break;
}
if (!is_file_exist(psz_log_file_pathname)) {
break;
}
pf = fopen(psz_log_file_pathname, "r");
if (NULL == pf) {
break;
}
memset(sz_buf, 0, sizeof(sz_buf));
while (NULL != fgets(sz_buf, sizeof(sz_buf), pf)) {
if (NULL != strstr(sz_buf, "Discovered credentials for rdp on")) {
MYLOG_D("%s", sz_buf);
i_rc = EXIT_SUCCESS;
break;
}
memset(sz_buf, 0, sizeof(sz_buf));
}
} while (0);
if (NULL != pf) {
fclose(pf);
pf = NULL;
}
return i_rc;
}
std::string get_pathname_from_pid(pid_t i_pid)
{
std::string str_path;
char path[PATH_MAX] = {'\0'};
char dest[PATH_MAX] = {'\0'};
memset(dest, 0, sizeof(dest)); // readlink does not null terminate!
// struct stat info;
sprintf(path, "/proc/%d/exe", i_pid);
if (readlink(path, dest, PATH_MAX) == -1) {
// perror("readlink");
} else {
str_path = dest;
}
// /home/dev/rdp_login_verify/rdp_login_verify
return str_path;
}
bool is_file_exist(const char* psz_file_pathname)
{
bool b_rc = false;
struct stat buf;
do {
if (NULL == psz_file_pathname) {
break;
}
if (-1 == stat("psz_file_pathname", &buf)) {
} else {
b_rc = true;
}
b_rc = true;
} while (0);
return b_rc;
}
#!/bin/sh
# @file test_case.sh
# @brief test how to call rdp_login_verify
fn_print_empty_line() {
# $1 is parameter 1
for i in $(seq 1 1 $1)
do
echo
done
return 0
}
fn_test() {
./rdp_login_verify -ip 192.168.2.61 -port 3389 -user administrator -pwd 111111
# print function's return value
echo $?
return 0
}
main() {
# clear screen
clear
# print 25 empty lines
fn_print_empty_line 25
# test
fn_test
}
main
exit 0