什么是你见过或做过的最酷的黑客?
作为程序员,我们都把一个非常酷的程序放在一起,或者以一种有趣的方式拼凑一些硬件来解决问题。 今天,我正在考虑那些黑客行为,以及他们中的一些如何被现代技术所废弃(例如,你不再需要破解你的Tivo来添加一个networking端口)。 在软件世界里,我们把网页上的东西拖放到现在是理所当然的,但是不久之前这也是一个非常令人兴奋的黑客攻击。
我见过的最恶劣的硬件攻击之一是几年前在一家电信公司的一位前同事完成的。 他在办公室里有一台小型的便携式电视机,他一整天都在看电视。 为了摆脱这种危险,他把一个开关连接到了桌子底下的脚下。
什么是你亲自看到或完成的最酷的硬件或软件破解? 你现在在干什么?
我记得这是由鲍勃·史密斯(Bob Smith)写的,这个老的DOS时代的内存pipe理器叫做386MAX(或“386到Max”)。 这不是产品的一部分,这是一个小小的实用程序,他鞭打并张贴在某个地方。 然而,在网上,我能find的这个技术的唯一参考是1996年11月由罗伯特·柯林斯(Robert Collins)撰写的DDJ Undocumented Corner专栏。
问题
在Intel引入CPUID指令之前 ,很难检查系统中CPU的确切types和修订级别。 事实certificate,在386及更高版本的大多数版本中,实际上都有一个CPU ID,但是它只在一个特定的时间可见:EDX寄存器中的处理器复位后。 (假devise算机的BIOS是唯一合法的软件)。
问题:如果我们不是BIOS,普通程序如何检索这个寄存器值?
背景材料
这种攻击依赖于IBM PC兼容计算机的六个不同的特性。 他们如下:
- 从IBM AT和更高版本开始,可以独立禁用总线上的A20地址线 。
- 大多数电脑没有将RAM安装在BIOS ROM下面的高内存地址中。
- 读取没有安装内存的内存位置时,大多数IBM PC总线计算机将返回0xFF。
- 0xFF 0xFF 0xFF等是Intel CPU上的非法操作码。
- 如果你在内存中安装了一个exception处理程序,它将在这个时代的大部分CPU(386到486)上软重启。
- 在软重置或硬重置时,Intel处理器跳转到可寻址存储器顶部的地址减去16个字节,这就是为什么BIOS ROM被放置在那里的原因。
该scheme结合了所有这些琐事的知识,以达到目标。
黑客
结果是一个DOS命令行程序,它执行以下操作:
- 安装了一个非法的操作码exception处理程序
- closures总线上的A20地址线
- 软重新启动CPU(我认为这是通过BIOS调用)
当发生软重启时,处理器会尝试跳到内存的最顶端减去16个字节,这是ROM启动代码所在的位置。 但是,由于A20closures了,它实际上会跳到内存的顶部减去16字节减1兆字节 。 在大多数电脑上没有RAM。 所以它会从这个不存在的RAM中读取一系列0xFF字节,并尝试执行它。 这将创build一个非法的操作码exception。
然后他的exception处理程序将挖出EDX(CPUID)的值,并将其存储在某个他可以find的地方。 然后清理混乱(重新打开A20,从保护模式翻转到DOS的实模式)并将控制返回到原始代码。
当它工作的时候,这是天才。 瞧,这是一个简单的命令行DOS程序,会给你的CPUID值。
当然,那里不可避免地出现了那些“不太兼容”的电脑,当你运行这个电脑的时候会崩溃。 呃,好吧。
quake3反平方根和MIT Magic / More Magic开关通常会制作这些列表。
那么这不是最酷的,但对于程序员来说这绝对是有趣的。
我们为一个简历数据库项目构build了一个专门的查询生成器。 有一些AJAX的部分,基本的想法是,如果你改变了页面上的任何东西 ,search自动重新运行自己。 (它是由所有UI小部件的onBlur事件触发的)
所以我们没有真正使用“search”或“运行查询”button。 这使用户陷入了无尽的困境。 所以我们添加了一个什么也没做的searchbutton。 它只是坐在那里。
它的工作原理是因为每次点击searchbutton时,你刚才所在的字段中的onBlur事件都会触发。
这使我们的用户群非常高兴。 简单的事情。
这不是我做的破解,而是我曾经工作很久以前的一个人告诉了我(他实际上做了破解)。
看起来他曾经是一个盲人,需要阅读文本文件的人。 于是他想出了如何将文本文件翻译成盲文,并使用各种字符打印出来。 和:
当时的打印机是冲击式打印机,所以当打印字符时,打印机构足够大地打印纸张,留下可感觉到的印象。 由于在纸张背面形成的印象,他不得不打印倒置的盲文,以便当纸张翻转时,这是正确的。
当然,阅读的行为消除了萧条,所以它是一个只读的机制,但我一直认为这是一个非常酷的黑客。
在开展iPhone的逆向工程工作时,我发现基带(处理电话和载波锁的芯片)存在一个漏洞,允许您随意写零。 尽pipe起初这似乎毫无用处,但很快显而易见的是,这可能比我最初想象的要多得多。 通过ARM的工作方式,可以通过在目标中写入一个零来使某些跳转无效,从而导致执行path始终继续前进。 这使得一个软件解锁,但很快被更强大的黑客所取代,允许你完全重新刷新基带。
无论现在它的无用,还是该为这种黑客而自豪。
我在大学里用气动阀门制造了一个8分的计数器,以便免除余下的气体学课程。
它是这样一个微不足道的东西,但当我第一次看到这个代码(由我的一个开发人员),我感到震惊,因为这是我从来没有想到的(我join的评论):
cglobal x264_sub8x8_dct_sse2, 3,3 ;3,3 means 3 arguments and 3 registers used .skip_prologue: call .8x4 add r0, 64 ;increment pointers add r1, 4*FENC_STRIDE add r2, 4*FDEC_STRIDE .8x4: SUB_DCT4 2x4x4W ;this macro does the actual transform movhps [r0+32], m0 ;store second half of output data movhps [r0+40], m1 ;the rest is done in the macro movhps [r0+48], m2 movhps [r0+56], m3 ret
它一次做8×4组的8×8块4变换。 但是它不会粘贴代码两次(这会浪费代码大小),也不会有8×4的函数并调用它两次。 它也没有一个循环。 相反,它调用“函数”,然后递增指针,然后“落入”它并再次执行。
它得到两全其美的好处:没有函数调用超出原始的开销(因为指针r0,r1和r2在SUB_DCT4中不增加) ,没有代码重复, 也没有循环开销。
今年夏天我写了一个叫做SatelliteRush的游戏。 这是一个突破游戏的手机与Java和GPS。 它可以播放两种模式:“无聊模式”和“卫星模式”。 在无聊模式下,您可以像往常一样使用button来移动桨,但在卫星模式下,它会使用手机的GPS接收器。 你跑来跑去,桨板随着你移动。
我只testing过索尼爱立信W760i,它的工作原理相当不错,因为GPS位置更新相当缓慢和不精确。
到目前为止,我已经做了这个游戏的“技术testing版本”,所以它不是很好看或易于使用。 但是,如果你有一个Java的GPS手机,你可以在这里下载: http : //www.lysator.liu.se/~padrone/temporary/SatelliteRushTest/
编辑:
现在可以在Android Market上作为Android Market的免费应用程序使用: https : //market.android.com/details?id = se.nekotronic.satelliterush
达夫的设备 。 这算不算? 🙂
达夫设备 ,为上述问题。
梅尔的故事 。 硬核黑客。
我有一个早期的Commodore 64计算机,需要为它编写汇编代码。
问题是,没有C64的汇编程序(无论是,还是我买不起)。
所以我通过在一本书中查找6502操作码来编写汇编程序,并从原始字节中创build程序。
在某个时候,它能够将汇编代码作为input,并汇编成一个程序。
我的一个朋友在BASIC为他的PET写了一个反汇编程序。 我使用这个程序来拆卸我的汇编程序,然后可以使用我的汇编程序来汇编自己的更新版本。
哦,我们不得不跳过旧的日子:)
我创造的最酷的破解(这真的不是真正意义上的破解,但它通过以及一些上述的答案),我曾经创造了我的苹果/ /电子。
参考手册中有一行表示$ C010是“任何关键”标志。
结果是真的。 $ C010软开关的高位会告诉你一个按键是否closures,尽pipe内置了按键重复硬件。
他们没有告诉你,每个人都发现了困难的是,没有可靠的办法找出被按下的键。
如果你写了一个小程序…(原谅我的错误,我的6502程序集很生锈)
:1 lda $C010 cmp #$80 bcc :1 ; branch if less than? I forget how to do that. lda $C000 jsr $FDF0 ;output the accumulator value to the screen
所以它会循环直到你按下一个键,并通过从$ C000键盘读取开关加载来输出键。
但是如果你运行这个程序,那么这个程序就不太合适。
当你拿着钥匙的时候肯定会打印出一些东西,但是当你不在的时候什么都没有,但是公共汽车上有一点点滞后(我想我不是一个硬件人),所以如果你按下“f”键会得到很多的f。 但是,如果你停下来,然后按'g',你会得到一堆'f',然后切换到'g'。
你可以在苹果中看到这个问题的证据] [Gauntlet的版本,你会向一个方向移动,如果你尝试向另一个方向移动,那么你会沿原来的方向移动一点,直到你通过滞后。
这是毫无意义的,因为阅读$ C000总是100%准确的,除非你先拿到$ C010。
我发现这个问题令人着迷,经过几周的游戏,我终于想出了我仍然认为是我写过的最酷的程序。
程序本身没有意义,它做了几个无用的ORA,但由于某种原因它工作,并且在查询$ C010之后从$ C000产生了正确的值。
太酷了,我写了一篇关于蚕食杂志的文章,他们接受但是从来没有发表过(或者是因为他们倒闭了,或者是因为这篇文章是15岁的写的,那是我写的)键盘input程序,并将其挂接到每个人都呼叫的零页位置,以获得键盘input,并且我能够以编程方式更改键盘重复延迟和重复速率,否则这是不可能的,因为它连接到硬件。 当然,苹果电脑公司当时正在出路,但直到今天,我还是最酷的。
更新3/2/2010:通过一些旧的文件,我发现我的小程序集打印输出。 我在这里发布,看看有没有人能弄清楚它为什么会起作用,所以它永远会被放在数字forms的某个地方。
$0300 AD 10 C0 LDA $C010 ; load accumulator with any-key-down flag $0303 29 80 AND #$80 ; keep only high bit flag $0305 0D 00 C0 ORA $C000 ; OR accumulate with keyboard soft switch $0308 10 F9 BPL $0303 ; erm, I forget exactly which branch this is $030A 09 80 ORA #$80 ; turn the high bit on $030C 20 ED FD JSR $FDED ; print char in accumulator $030F 4C 00 30 JMP $0300 ; start again.
没有道理,为什么这应该工作,但它确实。 还是做了。 25年前。
快速反向平方根 – 一种奇怪的小程序,以某种方式设法计算某些东西的平方根,但是你从来没有从中看出这一点。
http://betterexplained.com/articles/understanding-quakes-fast-inverse-square-root/
我的一个朋友正在用更新,更快的OEM主板取代戴尔的主板。 然而,他不能得到电源button,和其他前面板的东西,工作 – 连接器是不同的大小,不同的引脚布局。 我拿了一堆备用跳线和备用电线,并一个一个地连接好适当的引脚。 不需要焊接:)
代码方面,我不断被印象深刻。 我一直认为没有一个确定一个fork
孩子是否成功exec
,但实际上是这样 。
儿童:
execvp(argv[0], argv); errval = errno; write(data->fd, &errval, sizeof(errval));
父:
socketpair(AF_UNIX, SOCK_STREAM, 0, fds); flag = fcntl(fds[1], F_GETFD) | FD_CLOEXEC; fcntl(fds[1], F_SETFD, flag); pid = clone(child, NULL, SIGCHLD, NULL); if(pid < 0){ ... } close(fds[1]); /* Read the errno value from the child, if the exec failed, or get 0 if * the exec succeeded because the pipe fd was set as close-on-exec. */ n = read(fds[0], &ret, sizeof(ret)); if (n < 0) { ... } else if(n != 0){ /* exec failed */ } else { /* exec succeeded */ }
史蒂夫·沃兹尼亚克的磁盘控制器 。
我们被一些据说是俄罗斯黑客的小公司妥协了。 我自己和其他一些开发人员想知道怎么做,于是我把我从服务器上看到的最优雅的PHP脚本删除了,并且立即从我们的活动机器上删除了它。
这是一个名叫c99shell的特洛伊木马,它的function如此之less,以至于同时又可怕又美丽。 东西有一个embedded式graphics用户界面的图像使用base64从PHP输出,所以一切都是自足的。 function列表不舒服! 这个东西可以启动shell,扫描连接string,locking自己,并为攻击者提供许多其他有用的东西。
它过去挺美。
办公室里的每个人都认为我很疯狂,但是真的,这个代码真的很值得考虑。 他们把文件的大小保持得很小,以便偷偷的超过那些讨厌的上传限制,甚至还有一个base64编码的电子邮件通知,它收集了攻击者的所有信息。
特斯拉的设备创造了人造闪电 (42米或130英尺)的logging,科罗拉多斯普林斯的所有灯光都熄灭了。
黑色星期天黑客 。
我会告诉你,但是如果我承认的话,他们可能想要我的高中文凭;)
回到DOS时代,我写了一个脚本程序来演示我公司的软件。 这个脚本程序将启动应用程序,然后在应用程序的顶部popup窗口,使用animationtypes描述它的一些function,然后closures窗口,向应用程序提供按键,等待应用程序显示正确的屏幕,然后popup更多的窗口。 它有自己的脚本语言,甚至脚本编辑器,所以我可以中断脚本,编辑它,然后继续运行。 最好的部分是,它运行在我们的应用程序的未修改版本之上。
整个演示应用程序是用C语言和汇编语言编写的。 它挂钩了计时器和键盘中断,以便与应用程序交互。 我写了一切,包括窗口库。
在大学讲座中,我曾经一起攻击了psion 3a的一个简单的dos式命令行。 它只能做基本的目录列表,浏览,复制和移动,但它看起来是部分 – 全屏一个小字体。
哦,我编程的庞大的68008与盆input和示波器输出。 使用开发板并不那么困难,但是在一个osc上播放它还是很酷的。
当然不是我自己做的,但我最近碰到它,看起来很酷:
C#中的自我打印游戏
“康威的生命游戏几十年来一直令计算机科学家着迷,即使它的规则简单得可笑,康威的宇宙也产生了各种各样的滑翔机,飞船,振荡器,滑翔机枪和其他forms的”生命“。同样好奇,而且相当惊人 – 在计算理论中占有重要地位。
当你把两者结合起来会发生什么? 你即将发现,但有一点是肯定的:geekiness因素应该是相当高的。
我写了一个包含生命游戏网格的C#程序。 该程序将游戏网格推进到下一代,并打印出自己的副本,并更新网格。 你可以拿出输出,用C#编译器编译,运行它,你就可以得到下一代游戏。 您可以迭代该过程,也可以手动更改初始网格状态。 “
按照上面的链接源代码。
我写了一个简单的Windowsbatch file,让我在一台速度很慢的机器上快速播放与我的音乐库(f:驱动器)中某些模式匹配的音轨(iTunes需要3分钟左右!)。 它通过findstr
命令支持正则expression式,并使用mplayer播放曲目。 我所要做的就是按Windows + R键入:
play u2
要么:
play "neighbo.+rhood"
要么:
play "blink[0-9][0-9][0-9]"
batch file是这样的,在play.bat
。
cd /df: findstr /I /R %1 dirlist.txt > playlist.txt mplayer -playlist playlist.txt
mplayer和play.bat都应该添加到你的path。
我用Excel和Visual Basic编写了一个小型虚拟机(UDVM)的汇编程序。 在Excel单元格中写入汇编代码,在另一个工作表中编写内存布局,然后在底部计算机器代码二进制string。 想象一下,每当你改变你的汇编代码时,手上的assembly恐惧。
经过几天的debugging,发现有一个不能接受的掉话次数的拨号服务器,我将这个问题追溯到一个本土的authentication机制,这个机制依赖于正在运行的getty
的PID的文本表示。 如果它的PID包含一个偶数然后是9, getty
将产生一个错误并中止,从而导致掉话, getty
重新生成一个新的PID。
问题确定之后,我就离开了项目,后来发现“修复”是将数字到文本的转换从
sprintf(strval, "%d", pid);
至
sprintf(strval, "%o", pid);
而不是排除authentication程序的故障,有人select将PID转换为八进制 ,因此无法包含9!
而C#中的一个自我打印程序('quine'),长度为149个字符:
C#Quine
class P{static void Main(){var S=“class P{{static void Main(){{var S={1}{0}{1};System.Console.Write(S,S,'{1}');}}}}”;System.Console.Write(S,S,'”');}}
几年前,我开发了一个Web界面,并使用一些全新的JS库来实现AJAXfunction。 该lib只评价了html文档头中的JS,但是返回的数据太多以适应头文件。 该怎么办?
一些戳头显示头中的JS可以访问html文档的主体,所以我写了一个通用的“eval body”函数,它在头文件中返回。 当时非常有用,特别是b / ca不同的JS库,我们只评估从身体中的JS,所以这是兼容的JS库和避免任何大小的限制!
是的,很简单,但是在弄清楚这一点之后,整整一个月我感觉非常棒
看到我的前工作人员在三个星期内从头开始在汇编程序中重写了一个3D引擎。 旧的是慢,我们没有时间去改变graphics资产了。 他在截止date前两个月开始重写。
这是同一个人(还有其他一些人 – 这是一个团队合作的行为)谁做了一个惊人的工作10分钟的graphics和声音到一个64kb的可执行文件。
在研究如何在4D中使用TCP时,我在文档中遇到了Duff设备的这个变种:
$SentOK:=False //A flag to indicate if we made it through all of the calls Case of : (SMTP_New ($smtp_id)!=0) : (SMTP_Host ($smtp_id;<>pref_Server)!=0) : (SMTP_From ($smtp_id;vFrom)!=0) : (SMTP_To ($smtp_id;vTo)!=0) : (SMTP_Subject ($smtp_id;vSubject)!=0) : (SMTP_Body ($smtp_id;vMessage)!=0) : (SMTP_Send ($smtp_id)!=0) Else $SentOK:=True //message was composed and mailed successfully End case If ($smtp_id!=0) //If a Message Envelope was created we should clear it now $OK:=SMTP_Clear ($smtp_id) End if
我看着它,认为这真的很聪明(我仍然这样做)。 不幸的是,这不是我所需要的,我从来没有机会使用它。
不是由我:
#include <stdio.h> #include <string.h> int main(int argc, char *argv[]){ int i; printf("(((("); for(i=1;i!=argc;i++){ if( strcmp(argv[i], "^")==0) printf(")^("); else if(strcmp(argv[i], "*")==0) printf("))*(("); else if(strcmp(argv[i], "/")==0) printf("))/(("); else if(strcmp(argv[i], "+")==0) printf(")))+((("); else if(strcmp(argv[i], "-")==0) printf(")))-((("); else printf("%s", argv[i]); } printf("))))\n"); return 0; }