bookmark_border无事也要写日志,写给未来的自己看

博客不再流行真的是有他的道理的。文采好的,去各大平台开专栏开公众号了。只是想记录生活的,微博朋友圈更轻松,还能收获更多评论,开心。

我对我博客的定义比较模糊。

首先作为程序员,写博客的第一印象肯定是技术博客。可是翻了翻我至今为止的日志内容,称得上技术的真是少得可怜,就算有,很多也是我学会或者攻克某个技术细节之后的文字总结,并不是通常意义上给新手入门用的技术日志。

因为想听听其他熟人的评价,所以曾经把博客介绍给同事看了,结果被说都是“无病呻吟”,没有技术含量…

虽然有点受伤,不过人家说得没错啊,想在我这里学到技术,还不如问自己波棱盖儿呢(突然想起这句老话,强行用上=v=)。

最初把博客改名盗贼的极意,本来是想敦促自己要从公司或者其他可以接触到成熟解决方案的地方“偷师”,即使与自己无关的部门的技术框架也要偷学回来的。但是现在看来,我这其实不是个讲技术的地儿啊。所以这个新名字,就单纯的用来耍帅吧。

 

技术博客是做不了了,那就记录生活吧。

说记录生活也有点说大了,我这里更多的是记录一些心情,想法。

翻翻五六年前的日志,看到当时我的希望在工作中不计较工资,以吸取技术经验为主,现在看来真是惭愧得很。对现在的我来说,技术已经不是一个遥远到需要虔诚仰望的存在了。比起追求模糊的“技术”这一概念,现在的想法更加具体。我知道我需要学习什么,也知道怎么学,甚至也知道自己肯定能学会。当一切变得唾手可得时,它也同时失去了曾经的神奇魅力。

现在的我,更想做事。想用自己的技术去做成些什么。公司内的项目也好,兴趣项目,玩具app,网站,游戏,什么都好。而做成一件事所需要的能力很多,技术只是其中最容易入手的一种,容易到你甚至可以不懂技术,只靠外包来完成项目。

说远了。还是说说记录心情吧。

我是一个行动力执行力自控力很差的人,日语叫对自己太好(自分に甘い),想放弃就放弃,我甚至很想在简历里添一句“擅长放弃”。因此日志里有很大一批自我激励的鸡汤类内容,也就是同事说的“无病呻吟”了。说实在的,总是自我反省,总是立大志,然后总是放弃,连我自己都不好意思再写这类日志了。我也想像其他我佩服的人一样,某一天冷不丁甩出一篇日志说,我最近做成了这个这个这个,然后附上github链接,超吊。

可能立志这件事,说出来就不灵了吧。

bookmark_borderchrome 的 tab 设计恶心到我了!

每次多开一点tab他就隐藏网站图标,让我摸黑使用,怎么用嘛!

useless-tab

 

本来前一版(67.0?)那个锯齿状tab的解决方案蛮好的,怎么这两天又给改没啦?!

 

锯齿状tab

 

好吧,在这里立下Flag,等我的nes模拟器写完,下一个就是定制自己的锯齿状tab的chromium!

bookmark_border【兴趣】3D打印,自制游戏主机

 

donkey-kong

最近突然想知道怎么做游戏模拟器。
这个念头从我学程序开始就每隔几年冒出来一次。从当时毫无头绪,到后来知道simulator和emulator的区别,再到前些天看到这篇博客,我终于觉得我已经可以实现这一目标了。

这时候就不得不提一下我的一个坏习惯了。是这样的,我面对一个难题或者个人项目时,总是一开始非常有热情有行动力,但是当我知道我能完整的解决这一难题,或者我已经了完成个人项目中最大的技术挑战时,我的热情会瞬间退却,最终导致项目停滞,最终弃坑。
这次为了防止弃坑,我决定连游戏主机也自己diy一个。这样模拟器的实现就只是项目中的一小部分,有可能我最终弃了diy主机的坑,但完成了模拟器呢(笑)。

diy游戏主机,具体来说是掌机,其实就是想做一个塑料的机壳,里面跑个树莓派,整体上有屏幕有按钮有电池有张sd卡就够了。
这里最大的困难是这个外壳大概要自己定做。不过既然已经时这个时代了,我猜个人3D打印应该足够满足我的需求了。

说是这么说,心里还是没底,于是查了查3D打印方面的行情。第一个想到的当然是万能的淘宝啦。上去搜了搜,cad来图定制似乎挺成熟的了,做这门生意的人很多,生意也不错。那么下一步就是找到这个行业里最主流的供应商了。淘宝上销量好的很多,似乎没有谁是统治级的,但有趣的事,我看到很多卖家下面的买家秀的包装盒都是同一款。这什么情况?搜了一下盒子上大大的“wenext”的logo,找到了未来工场,一个3D打印服务提供商。在他们的网站上传stl后缀名的cad文件可以实时算出预算,运送方面用的是顺丰,我特意问了一下,可以选择稍微慢一点但便宜很多的顺丰国际特惠来送到日本。价格来说是可接受范围内的,即使算上国际运费。看来这就是我要找的“行业里最主流的供应商”之一了。至于淘宝为什么用这家的包装盒,我猜可能是淘宝店家接单后转手去未来工场订货,再转卖给买家的吧。虽然之后又搜到其他几家国内的可以在线计算预算在线下单的3D打印网站,不过考虑到淘宝卖家一致的选择,我也决定随大流选未来工场了。

(后来我甚至发现了一个未来工场的山寨网站“未来工厂”!我问未来工场的客服说这个是你们的分部吗?他说我们没有关系,我们是未来工“场”,他们是未来工“厂”。哈哈哈哈,简直大家来找茬啊!他说了我才发现真不是同一个场字。会被同行山寨更坚定了我选他们的决心!)

为什么不直接在日本找3D打印公司呢?因为贵啊!随便搜到几家,根据同个cad图得出的费用是6万到8万日元,折合人民币要三四千块了。未来工场这边只要几百人民币,完全碾压。
其实美国也有一家主流的3d打印网站(all3dp.com)。它上面是以3d打印信息文章新闻之类的为主,但是也有在线上传图纸,下面列出各家供应商给出的价格,类似一个卖家聚合网站。不过算上运费,美国供应商提供服务的性价比也完全比不上中国,同一产品成本大概是国内两三倍的样子。

打印商定好之后,下一步就是要选一个适合的cad软件,做我的设计图了。能学一下cad,感觉不错啊,以后能做的事就多多了。

bookmark_border近期工作内容记录

unnamed

工作上遇到 android app 意外发生 Bitmap 内存泄漏的问题。把 vm heap dump 下来一看不得了,有大量 byte[] 数组驻留在 vm 内存内,但却没有被任何对象引用到!明明我们的 app 内存不足到都崩溃了,gc 还不回收这些垃圾 byte[],这是为什么?而且这个现象在 android 6.0 上发生,但在 android 7.1 和 8.0 上都不会发生。而且,在我们的 app 退出那个会导致这个内存泄漏的 view 之后,gc又可以正确回收那些幽灵数组了。总觉得,好神秘!
稍微读了一下各个版本 android 的 Bitmap 的 java 和 jni 代码之后,我觉得这是因为内存虽然被标记为虚拟机内内存,但是创建和释放都是由 native 层管理着,而 native 层出于某些原因,不愿意及时释放这批内存所导致的。是一起有组织有预谋的私藏内存事件。
怎么办呢,native debugger attach 上,直接调试 native 层吧,没有 symbols,看不到源码和变量,只能看到进入了哪个函数和任意时刻寄存器的数值,这调试起来真是两眼一抹黑,事倍功半。
想要有源码调试?可以啊,自己编译 aosp (android open source project),用自己编译的 system.img 启动模拟器就可以有源码调试了。于是花了一个星期各种式错后终于用上了自己的 system.img,自豪!结果发现用我的 system.img 之后内存就不泄漏了。耍我哦!
细致调查后发现不仅替换整个 system.img 会这样,就算只是替换掉 android 主机(模拟器)内的 /system/lib/libandroid_runtime.so 为我编译的版本,内存泄漏问题也会消失。这个 .so 里大概都是 android jni 相关的东西,当然我怀疑的 Bitmap native 部分的实现也在里面,所以我的推理方向似乎是正确的。只是没法继续直球出击分胜负了,遗憾。
顺便说一下,用 android studio 的 android profiler 的 memory 面板查看就会发现,用了我的 .so 之后 app 的 native memory 使用量始终非常低,而 原版模拟器会在 load 一个 Bitmap 后 java memory 和 native memory 会一起增减。目前我初步怀疑是我编译的版本没有能够正确访问硬件相关功能导致硬件加速部分产生了差别,但还没有什么证据。
如果是兴趣项目,我肯定会继续研究 aosp 的,可惜这次是工作,不能太任性。下一步我准本静态分析 Bitmap 相关的代码,配合半瞎的 native debugger 和试错性调整相关的 react-native 部分代码来找出避免这一内存泄漏的方法。
之前遇到过 react-native 的圆角图片导致的 android 7.1 以下的 app 会发生 graphics memory 内存无限泄漏的问题,最后也是在没理解根本原因的情况下被我绕过去了,相信这次也能逢凶化吉!

bookmark_borderMD维护一个写的狗屎一样的php项目真的恶心,还TM的是自己写的,日

当年年少无知,什么框架都没深入用过,只靠着会写php语法就接活做了网站。

为了避免遇到难以解决的问题来不及交货,于是决定不用任何框架,结果最后徒手写了一百多个php文件硬凑起一个网站来。

随着规模的增大,每增加一个新功能都提心吊胆。一直想写自动测试写回归测试却无从下手。

现在还要为这个网站做微信网页版适配,真是有种抽积木的自虐快感。

抽积木

现在还能怎么办呢。因自己的无能而酿下的苦果,只能硬着头皮接受了。

以今日之耻为鉴,日后定要练成体系化网站开发的扎实功底!

bookmark_border用了好几年的chrome扩展竟然有后门?!

malware

今天上班,刚打开fiddler就在自己的http log里发现了一条发自chrome扩展程序的可疑request。

打开这个扩展的chrome web store页面发现已经被下架。
网上搜了一圈发现有人有同样疑问,虽然没有完全解开谜团,但基本可以确定是可疑程序了。
打开扩展的js代码看了一下,全部重度混淆,果然是做贼心虚。
最可气的是他的代码中竟然包含 function(data){eval(data);} 这样的执行任意代码的后门,我操!

插件名: “Classic Scrollbar Buttons”
这是一个让chrome重新使用老式右侧滚动条外貌的常驻扩展。我已经用了很多年,竟然直到今天才发现带后门,真是……无语。
暂时先把它发出的request信息原样保存好,插件暂时禁用,等我有空了再回来收拾你。

bookmark_border记与黑马君长聊

mariokart8

时隔大约半个decade,终于又一次听到了D-Horse同学的声音。喜闻君亦入行IT,感慨良多。

连打6个小时的电话怕是我个人生涯的最高纪录了,话题竟然够讲这么久,我自己都觉得有点不可思议。

跟你倾诉我社交生活太少感觉寂寞之类凡人的苦恼,现在想想自己都觉得不好意思。这种事还是应该自己内部消化才比较成熟。不过谁让我们就是从幼稚时就相识的呢,这点任性,想你应该可以体谅:)

两个人联机马车确实是不如一大群人一起玩有意思,不愧是party game。下次看看有没有什么暗黑2那样两个人可以一起闯关,平时也能自己推进的游戏吧。明年王者荣耀如果评价不错,可以考虑联机一手,如果账号可以跨服联机的话。

关于理想的工作,我也有同样的苦恼,也是正在理想与现实之间难以做出抉择。只恨自己技不如人,年轻时没有花时间去精进自己的手艺,积累作品,落到现在不能随心愿选择工作的处境。不过过去的已经过去,现在的我是疯狂揽活填充业余时间,希望5年后的自己不会再同样怨恨现在的自已吧。

跟你说的我信息成瘾的事,正好在这里记下来提醒自己。今后刷微博刷新闻的时候要提醒自己停止,就像当年成功戒掉了愤世嫉俗关注政治新闻的习惯后,发现我的生活并没有因为缺少政治信息而有丝毫褪色一样,相信停止疯狂吸收信息也不会摧毁我的现有生活。省下来的时间嘛,把自己买的kindle电子书先消化一下吧。拿来玩游戏也很不错。我现在正处在怀疑自己是否真的喜欢游戏行业的自我怀疑阶段,多玩一些主机和PC游戏,让我仔细感受一下自己还会不会为这个行业兴奋吧。每次去秋叶原走一走我都感觉自己的信仰得到了充值,赴日留学时的心情又重新浮现。我对游戏行业的热情也需要像秋叶原这样可以帮我为信仰充能的象征,希望能在玩游戏的时间里找到。

听你讲的德国的福利真让我有点动心。现在日本的养老金制度是交足10年就有资格领取,随便你在日本还是在海外,对外国人非常友好。如果今后有机会去欧洲找一下工作,也许也是不错的生活。不过因为语言等原因,去欧洲工作的话我可能会去英国,到时候去找你玩要靠划船坐飞机了。

趁我还在日本,快来日本玩呀!我也努力提升专业技能,给转职之路攒一些筹码,顺利的话转职间隙也会去找你玩的!

bookmark_border从 raid1 的单盘中取出文件

harddisk

今天用两块新硬盘,试了一下用synology创建raid1后,故意破坏其中一片硬盘,再从剩余的另一块硬盘中恢复文件。实测给synology一块新硬盘,它自己可以修复raid1。

不过比较尴尬的是,当我破坏raid1后再拔掉两块硬盘,然后重新插上,这时synology就无法识别这两块硬盘内的raid1了,更无法修复,这就很恶心了。

上网查了一下,修复方法是用linux下的mdadm挂载raid1中剩下的一块硬盘,从中取出文件。

 

先说一下,我是在windows虚拟机 hyper-v 里创建了一个 centos6.9 的虚拟机,把硬盘挂在虚拟机上测试的。

 

官方给的命令是

# mdadm -Asf && vgchange -ay

执行之后会增加一个 /dev/md*, 比如我这里增加的是 /dev/md4。有了这个md之后可以用

# mount /dev/md4 /{empty_folder}

命令挂载硬盘到指定目录,然后就可以从这个目录中访问原始 raid1 中的文件了。

用完以后用

# umount /{empty_folder}

解除挂载,然后用

# mdadm –stop /dev/md4

解除对 raid 硬盘的解析。

 

不过之前不知道怎么回事,官方命令我没执行成功。后来用 blkid , fdisk -l 等命令调查过,根据种种迹象得知硬盘上的三个分区,我需要的是 /dev/sdb3。

之后执行

# mdadm –assemble –run /dev/md127 /dev/sdb3

mdadm: /dev/md127 has been started with 1 drive (out of 2).

(这里md127是随便写的,应该不是非得用这个名字。)

之后执行

# mount /dev/md127 /{empty_folder}

挂载硬盘后,一样可以访问。

取消的命令分别是

# umount /{empty_folder}

或者

# umount /dev/md127

然后执行

# mdadm –stop /dev/md127

mdadm: stopped /dev/md127

 

值得一提的是,有人说需要用

# mdadm –examine –scan >> /etc/mdadm.conf

来修改配置文件,就可以在启动时加载磁盘阵列了,不过我这次只是想知道取出文件的方法,懒得重启测试了,这里只做记录,不再测试。

 

bookmark_border入侵自己家的监控摄像头 (二)

要找出HTTP服务器的漏洞,先要确定这是用的什么服务器软件。
我发现 404 response 的 Reason-Phrase 是“Site or Page Not Found”,而不是最常见的”Not Found”。搜索“Site or Page Not Found”发现这很可能是某个早期版本的 goahead 服务器程序。
搜索可知 goahead 程序在早起有很多bug,甚至包括远程执行任意代码的漏洞。不过直接试用执行远程代码的漏洞失败了…
有一天突发奇想,能不能从固件升级包中找到 goahead 的版本信息呢?于是下载了一个 firmware 的 bin 文件,用 Binwalk 打开后,找到了 goahead 的可执行文件。此时终于可以确定服务器端软件用的就是 goahead 了。
不过开发方也不是拿来就用的,它们似乎注释掉了源代码中关于 goahead 版本信息的代码,这就很恶心了。好消息是这个 goahead 软件是开源的,不过官方 repo 里只有从2.5版至今的代码历史,但根据可执行文件中的内容推测,摄像头中的 goahead 是一个早于 2.5 版的版本。为什么官方不提供更早的版本管理信息呢?看源代码,我才之前是用 svn 管理的代码,后来在迁移到 git 时直接复制进来,放弃了 svn 时代的代码历史。现在官网也不提供更早版本的下载了,无奈之下在 github 上找到了几个包含早期 goahead 版本的 repo,从中提取出了几个离散的早期版本的 goahead。有趣的是,我无论如何也找不到1.x版本的 goahead,我猜这个软件是进入2.x时代开始才改名叫 goahead 的吧。
那么,我是怎么根据可执行文件推测程序版本的呢?说来惭愧,用的是一个很土很低效的方法。
首先,goahead 是一个 c 语言编译出来的程序。c 语言的编译器我不是很了解,但是直觉上来讲,编译后常量字符串应该原样储存在可执行文件体内。搜索发现事实符合我的猜测,而且编译器会就近把同一个原文件中出现的字符串按顺序放在相邻的位置。
根据以上信息,我通过比较代码的变更历史,找到了一些仅出现在特定版本中的字符串和它们的排列顺序,最终确定我的摄像头使用的是2.1.4到2.1.8之间的某个版本的 goahead。
根据这个版本信息,我找到了几个可能可用的 goahead 的漏洞信息,但这些漏洞信息都只说漏洞适用于2.1版本,没有小版本信息,没办法只好根据代码推测漏洞是否依然可用了。

bookmark_border【开坑】入侵自己家的监控摄像头 (一)

养猫之后,家里架起了两台监控摄像头,以供我上下班无缝赏猫。

摄像头本身有ddns功能,但想想看自家的监控摄像头可以被整个网络直接访问到,纵使有密码保护,心里还是觉得很恶心的。所以我在公司都是用vpn连回家里,在家庭内网环境中访问摄像头。

事实上两台摄像头中有一台是几年前买来看家用的,另一台是为了看猫最近新买的高分辨率版。两台摄像头并不是同一厂家出品,外形也很不相同,但神奇的是网页端管理界面竟然迷之相似,我一度以为这是同一集团不同分公司的产品。

ipcam

后来经过我反复调查,发现这应该是某种现成的套件,各家厂商都在用罢了。

这个网页版管理界面做的可以说非常之 low。不说他杂乱的前端源代码,充满学生气息的界面设计,就连最重要的功能上都是严重缺失的。一个监控摄像头,竟然只有在IE下下载安装插件才能观看有声的实时直播,用 chrome 和手机浏览器都只能接收一张张的截图拼成一个幻灯片来看,声音更是甭想了。

我知道由于浏览器功能或者说 HTML 规则的限制,仅靠前端无法实现接收和播放 rtsp 直播流,但问题是服务器端也是你自家的啊,你做个 flv 直播流,做个 hls 直播流,怎么样都好,现成的库那么多,想让浏览器看个视频直播有什么难的= =

chrome 也真是讨厌,推翻 npapi 插件,又放弃了自家的 nacl 插件,跑去投奔一个不支持 socket 的 webassembly,导致我想自己写一个接收摄像头 rtsp 直播流的 chrome 插件都做不到了。虽然我也可以先写一个代理服务器,把 rtsp 流翻译成 flv 流或 hls 流,再用浏览器插件播放,可那很花功夫啊!我虽然喜欢写代码,但也会嫌麻烦的!

 

吐槽先放一放,说回到标题来。

从买到监控摄像头的第一天起,我就一直在担心摄像头被黑的问题。虽然我已经层层设防了,但每次进入摄像头的拍摄范围时还是时刻小心。没办法,我就是防人之心很重的人= =

想摄像头不被黑,先得知道摄像头会怎么被黑,然后才有办法防御嘛。再加上网络入侵本来就是一件对小青年很有吸引力的事,所以我开始好奇能不能入侵自己的网络摄像头。

参考这篇文章,我nmap了一下我的两台摄像头,发现并没有像作者遇到的情况那样简单的暴露出telnet端口或其他可疑端口。虽然证明我的摄像头更安全更不容易被人拿去搞ddos,但也让我更难入侵了…

直接登录不成,就从暴露出来的 http 服务器上找找线索吧。于是继续回来研究这个网页版后台。

大概看了一下,发现可能有多个服务器端程序在服务 http 请求:

看 response header 可知,服务器端的静态文件和 asp 脚本是跑在一个 http/1.0 服务器上的,返回的 server header 是厂商自定义的 “IPCamera-Web”。

另一方面,请求服务器上的 cgi 脚本或当请求返回 404 时,返回的 response 表明他的服务器使用 http/1.1 协议,此时返回的 server header 依然是厂商自定义的 “IPCamera-Web”。这个 1.1 的服务器的 200 response 总是会返回 “connection: close” header, 可见人家真的是 http/1.1 的服务器端呢。最后,当服务器请求失败返回 404 或 500 时,response 中不会携带 “connection: close” header,加上没有 content-length,也没有 chunked transfer encoding,仅从传输内容上已经无法判断这个 response 应该从何处结束了。不过从浏览器能正常访问后台页面这一点来看,1.1 的服务器端可能是发送 response 后直接断开了 connection,帮助客户端判断出了 response 的结束。不管怎么说,这最后一点使这个 1.1 服务器的实现显得很业余。业余好啊,说明代码中可能存在的安全隐患多,有助于我入侵系统。