QQ2011低级键盘钩子分析
0004DF8B1 55 PUSH EBP
QQ密码输入框(防键盘钩子)原理分析
01.网上看到的一些防星号查看器的代码大多是在后台维护一个字符串(真实的密码),界面则不显示真实的密码,这样做,维护那个字符串很费事,就因为我之前那样做过,我才在看到WM_GETTEXT后想要重做一个
2.防键盘钩子,在做上面的功能是,突然想到,如果自己模拟发一些乱七八糟的按键消息,然后自己区分哪些是垃圾哪些是用户真正的按键,那钩子就到不取密码了,所以又加了这个功能.后来自己做了一个钩子看了一下效果不错,试了试QQ的竟然也是这样,开始以为QQ用了什么高科技
3.自我感觉貌似实现了QQ密码框的功能,不知道会有什么问题,所以帖出来,谁有兴趣自己看吧
//////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
//safeedit.h
// CSafeEdit
class CSafeEdit : public CEdit
{
public:
//设置取密码时用的KEY(大于5)
BOOL SetPassWordKey(CString & astrKey);//取密码时用的KEY
DECLARE_DYNAMIC(CSafeEdit)
int GetWindowTextEx(CString & astrText);//astrText 传入KEY 传出密码
public:
CSafeEdit();
virtual ~CSafeEdit();
protected:
DECLARE_MESSAGE_MAP()
LRESULT OnGetText(WPARAM wParam, LPARAM lParam);
private:
BOOL mbCanGetText;//GetWindowTextEx:astrText == mstrKey ? TRUE : FALSE
CString mstrKey;
char mcLastVKey;//Timer 模拟的键
public:
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnSetFocus(CWnd* pOldWnd);
afx_msg void OnKillFocus(CWnd* pNewWnd);
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// SafeEdit.cpp : 实现文件
//
#include “stdafx.h”
#include “DlgTemp2.h”
#include “SafeEdit.h”
#include “.\safeedit.h”
// CSafeEdit
IMPLEMENT_DYNAMIC(CSafeEdit, CEdit)
CSafeEdit::CSafeEdit()
{
mstrKey = “jiawei@hotmail.com”;
mbCanGetText = FALSE;
mcLastVKey = 0;
}
CSafeEdit::~CSafeEdit()
{
}
BEGIN_MESSAGE_MAP(CSafeEdit, CEdit)
ON_MESSAGE(WM_GETTEXT, OnGetText)
ON_WM_CHAR()
ON_WM_TIMER()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
END_MESSAGE_MAP()
// CSafeEdit 消息处理程序
LRESULT CSafeEdit::OnGetText(WPARAM wParam, LPARAM lParam)
{
long lnStyle = GetWindowLong(GetSafeHwnd(),GWL_STYLE);
if(lnStyle & ES_PASSWORD)
{
if(mbCanGetText)
return DefWindowProc(WM_GETTEXT,wParam,lParam);
else
return -1;
}
return DefWindowProc(WM_GETTEXT,wParam,lParam);
}
//************************************
// Method: SetPassWordKey
// FullName: CSafeEdit::SetPassWordKey
// Access: public
// Returns: BOOL
// Qualifier: 设置取密码时用到的KEY,长度大于五
// Parameter: CString & astrKey
//************************************
BOOL CSafeEdit::SetPassWordKey(CString & astrKey)
{
if(astrKey.GetLength() < 5)
return FALSE;
mstrKey = astrKey;
return TRUE;
}
//************************************
// Method: GetWindowTextEx
// FullName: CSafeEdit::GetWindowTextEx
// Access: public
// Returns: int
// Qualifier:
// Parameter: CString & astrText 传入取密码用的KEY,如果成功返回密码
//************************************
int CSafeEdit::GetWindowTextEx(CString & astrText)
{
if(astrText != mstrKey)
return -1;
astrText = “”;
DWORD ldwLen = ::SendMessage(GetSafeHwnd(),WM_GETTEXTLENGTH,0,0);
if(ldwLen <= 0)
return 0;
char *lpszBuf = new char[ldwLen+1];
if(lpszBuf == NULL)
return 0;
mbCanGetText = TRUE;
ldwLen = ::SendMessage(GetSafeHwnd(),WM_GETTEXT,ldwLen+1,(LPARAM)lpszBuf);
mbCanGetText = FALSE;
astrText = lpszBuf;
delete [] lpszBuf;
return ldwLen;
}
void CSafeEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if(mcLastVKey != nChar)
CEdit::OnChar(nChar, nRepCnt, nFlags);
}
void CSafeEdit::OnTimer(UINT nIDEvent)
{
//随机生成按键
UINT lnVKey = ’0′ + (rand()%(‘Z’-’0′+1));
UINT lnScan = MapVirtualKeyEx(lnVKey,0,NULL);
mcLastVKey = MapVirtualKeyEx(lnVKey,2,NULL);
if(mcLastVKey >= ‘A’ && mcLastVKey <= ‘Z’)
{
BOOL lbLowercase = TRUE;
if(GetKeyState(VK_CAPITAL) & 0×01 != 0)//CapsLock ON
lbLowercase = !lbLowercase;
if((GetKeyState(VK_LSHIFT) & 0×80) != 0 || (GetKeyState(VK_RSHIFT) & 0×80) != 0)//Shift DOWN
lbLowercase = !lbLowercase;
if(lbLowercase)
mcLastVKey += ‘a’ – ‘A’;
}
keybd_event(lnVKey,lnScan,KEYEVENTF_EXTENDEDKEY,0);
CEdit::OnTimer(nIDEvent);
keybd_event(lnVKey,lnScan,KEYEVENTF_KEYUP,0);
}
void CSafeEdit::OnSetFocus(CWnd* pOldWnd)
{
CEdit::OnSetFocus(pOldWnd);
long lnStyle = GetWindowLong(GetSafeHwnd(),GWL_STYLE);
if(lnStyle & ES_PASSWORD)
SetTimer(1,500,NULL);
}
void CSafeEdit::OnKillFocus(CWnd* pNewWnd)
{
CEdit::OnKillFocus(pNewWnd);
long lnStyle = GetWindowLong(GetSafeHwnd(),GWL_STYLE);
if(lnStyle & ES_PASSWORD)
KillTimer(1);
}
相关评论:qq好象不是这样做的 因为我在截取QQ密码的时候发现QQ密码输入框输入的内容什么都截取不到 而不是截取到一大片乱七八遭的数据
这几天好好地研究了一下QQ2010登陆窗口的密码输入框,细节没有完全弄清楚, 不过还是看出了大致的原理了。在这里发表一下我的看法,和有兴趣的朋友一起讨论。菜鸟水平,认识问题的程度很有限,大牛们就飘过吧。
我首先想到的,是要搞清楚,他的保护原始是基于R0还是R3?
这个问题的答案是:R3。理由很简单,因为找不到QQ有驱动啊,所以自然就是在R3进行的保护了。这个没什么好说的,不讲了。
接着是,QQ究竟如何在应用层实现密码输入保护的呢?
这个问题一开始我想来想去都不明白。我的运气很好,后来无意中看到了QQ2010安装了两个很特别的windows消息钩子:WH_DEBUG和WH_KEYBOARD_LL,于是线索出来了。
看到这两个钩子,好特别啊,它们是做什么用的呢?为什么要安装这两个钩子呢?
我马上翻了一下MSDN,找到答案了。
原来,WH_DEBUG可以用来管理很多种类型的钩子,有这么多种:
WH_CALLWNDPROC
WH_CALLWNDPROCRET
WH_CBT
WH_DEBUG
WH_JOURNALPLAYBACK
WH_JOURNALRECORD
WH_KEYBOARD
WH_MOUSE
WH_MSGFILTER
WH_SHELL
WH_SYSMSGFILTER
WH_DEBUG能管理这些类型的钩子,在这些钩子的钩子过程将要被系统调用的时候,系统总是先执行调试钩子的钩子过程。而MS的这个调试钩子,允许我们决定是否执行这些被管理的钩子。
我扫了一眼以上列表,在其中发现了WH_KEYBOARD钩子。原来普通键盘钩子是被调式钩子所管理的,也就是说,如果一个程序装上了调式钩子,那么在它上面的普通键盘钩子的钩子过程在执行之前,先要执行调式钩子,而在这个调式钩子里就可以拒绝执行即将执行的普通键盘钩子。
想到这里我恍然大悟了,难怪QQ装有一个调式钩子呢,难怪有全局键盘钩子记录不到QQ的密码呢!
还有一个低级键盘钩子,这个比较难一点,QQ保护原理核心都在这里面。
想贴一下这个钩子的钩子过程的反汇编代码,想想还是算了,太太长了。还是说一下我理解出来的意思吧,不全面,没有完全弄懂。
首先要知道的是,低级键盘钩子和普通简单钩子执行的先后顺序。
如果一个程序,同时被装有这两种钩子的话。在按键消息到来的时候,这两个钩子的执行顺序是:
低级键盘钩子 -》普通键盘钩子
为什么是这样的呢?我是看MSDN悟出来的,有疑问的话你也看看吧。
既然低级键盘钩子在普通键盘钩子的前面执行,自然它也有防御普通键盘钩子的能力了。
看到前面两个钩子,都是能够防御普通键盘钩子的。我自然想到,如果盗号者采用的是低级键盘钩子呢?是不是就能取得QQ的密码了呢?
带着好奇,我自己做了一个低级键盘钩子的测试程序。结果发现:
当我用鼠标点击密码输入框,把输入焦点定在这里时(并没有按键盘),测试程序就不停地输出按键信息。奇怪,我还没有开始输入密码啊,一个键都还没按呢!
后来冷静下来想了一想,这一定是TX为了防止盗号木马使用低级键盘钩子取走QQ的密码,而故意设置的虚假的按键信息,这样即使你用低级钩子记录到了某个正确的按键,其中必然混杂了很多虚假的按键信息,形成了干扰。
最后还有一点很重要的东西,可能大家很容易忘记,我在这里提醒一下大家。
细细地回想一下以前学习windows钩子学到的东西,记忆里会想起这么一个规律:
如果一个程序上被装上了多了同一类型的钩子,那么这些钩子的执行顺序是,先安装的后执行,
后安装的先执行。
也就是说,如果给某个程序同时装上两个低级键盘钩子A和B,安装的顺序是:A -》B,那么这个钩子的钩子过程执行的顺序就是:B -》A。
所以说,如果我们给QQ安装上一个低级键盘钩子,因为我门是在后面安装的,所以我们的钩子应该先执行,然后才执行QQ自己安装的低级键盘钩子。这不是成了QQ键盘保护的弱点了吗?我一边想着,一边在怀疑。
这个问题QQ是处理的呢?我在实践中探索到了答案,原来QQ会通过一个定时器,不停地对它的调式钩子和低级键盘钩子进行Unhook,然后马上再Hook。这样,不是就保证了QQ的钩子安装在盗号木马的钩子之后,从而先于木马的钩子执行了吗?哈哈
最后用一句话概括QQ自己的低级键盘钩子吧,尽管细节我也没有完全看明白,但还是能猜出来了。
QQ通过给自己在应用层设置这个低级键盘钩子,并不断脱钩、挂钩,来保证自己在应用层上是最先得到键盘消息的。既然是最先得到了,那么接下来要进行保护就容易了,自然就是先取得正确的按键信息,然后阻止这个消息继续传递下来给别人,就算传下去交给别人,也要修改按键信息,传一个错误的下去。:)
仔细回想一下整个过程,发现也不是很高深嘛,以前把QQ的键盘保护看得太神秘了
我知道的就这么多了,希望有深入理解的朋友继续报料啊
相关评论:
我想了一个在应用层实现的办法:
先把QQ进程里的SetWindowsHookEx和UnhookWindowsHookEx废了,然后再安装低级键盘钩子来记录
实验了一翻这个办法是成功的,可是不知道为什么后来QQ的进程崩溃了。
不错。QQ的密码框还会产生干扰,按了的键会变成另一个键信息,会生成一些随机的按键信息
QQ用了一个定时器,不停得卸载自己的钩子,又马上重新安装,如此来保证自己的钩子总是在最前面执行的,所以只要把SetWindowsHookEx和UnhookWindowsHookEx废了,那它就没办法了
自己装个键盘过滤驱动不就得了?反正是从下面传上来的。或者挂csrss.exe的win32k!RawInputThread
到了做选择的时候了
0厌倦了每天在家泡着的生活了,出去走走也挺好的,找个地方坐下来翻翻杂志喝杯咖啡,也许慢慢就会忘记悲伤与不愉快,走在中关村的大街上总会有个想法,我什么时候能融入IT这个圈子?做个领跑者。或许这辈子都不会,越发的感觉在北京活着太难了,但我真的有勇气去南方发展吗?我也不知道…
介绍五种排序算法
0在程序对于数据的处理中排序是最基本的也是最常用的,排序算法有很多种,这里SC贴出五种排序算法的VB.NET实现,包括我们最熟悉的冒泡排序。还有例如箱排序等出色的排序算法没有贴出下次整理后贴出来。
Public Class clsSorter
Public Class BubbleSorter ‘冒泡排序
Public Shared Sub Sort(ByVal list As Byte())
Dim i As Integer, j As Integer, temp As Integer
Dim done As Boolean = False
j = 1
While (j < list.Length) AndAlso (Not done)
done = True
For i = 0 To list.Length – j – 1
If list(i) > list(i + 1) Then
done = False
temp = list(i)
list(i) = list(i + 1)
list(i + 1) = temp
End If
Next
j += 1
End While
End Sub
End Class
Public Class SelectionSorter ‘选择排序
Private Shared min As Integer
Public Shared Sub Sort(ByVal list As Byte())
For i As Integer = 0 To list.Length – 2
min = i
For j As Integer = i + 1 To list.Length – 1
If list(j) < list(min) Then
min = j
End If
Next
Dim t As Integer = list(min)
list(min) = list(i)
list(i) = t
Next
End Sub
End Class
Public Class InsertionSorter ‘插入排序
Public Shared Sub Sort(ByVal list As Byte())
For i As Integer = 1 To list.Length – 1
Dim t As Integer = list(i)
Dim j As Integer = i
While (j > 0) AndAlso (list(j – 1) > t)
list(j) = list(j – 1)
j -= 1
End While
list(j) = t
Next
End Sub
End Class
Public Class ShellSorter ‘希尔排序
Public Shared Sub Sort(ByVal list As Byte())
Dim inc As Integer
inc = 1
While inc <= list.Length \ 9
inc = 3 * inc + 1
End While
While inc > 0
Dim i As Integer = inc + 1
While i <= list.Length
Dim t As Integer = list(i – 1)
Dim j As Integer = i
While (j > inc) AndAlso (list(j – inc – 1) > t)
list(j – 1) = list(j – inc – 1)
j -= inc
End While
list(j – 1) = t
i += inc
End While
inc /= 3
End While
End Sub
End Class
Public Class quicksort’快速排序
Private Sub sort(ByRef arrValue() As Byte, ByVal intLx As Int32, ByVal intRx As Int32)
Dim strValue As Byte
Dim I As Int32
Dim j As Int32
I = intLx
j = intRx
Do
While I < j AndAlso arrValue(I) <= arrValue(j)
I += 1
End While
If I < j Then
strValue = arrValue(I)
arrValue(I) = arrValue(j)
arrValue(j) = strValue
End If
While I < j AndAlso arrValue(I) <= arrValue(j)
j -= 1
End While
If I < j Then
strValue = arrValue(I)
arrValue(I) = arrValue(j)
arrValue(j) = strValue
End If
Loop Until I = j
I -= 1 : j += 1
If I > intLx Then Call quicksort(arrValue, intLx, I)
If j < intRx Then Call quicksort(arrValue, j, intRx)
End Sub
End Class
End Class
不至于的吧。。。。
0也不只是真发火了还是什么。。。。心里一震的感觉。
是,有过不愉快的过去。以我对你的了解,你应该不会记仇的吧。。。。
或许这才是禁不起一点的触碰。。。。
心乱了,好可怕。
程序员新年要做的10个决定
0还剩不到一周的时间,我们将迎来2012年。我知道这是老生常谈,但今年你曾经有过什么样重要的经历?很自然的,我们现在正处于为新年许下目标的时候。也许你可能有“真实”生活中的一些目标,但是你的程序员生涯呢?
1 -学习一种新语言,框架或方法
我们必须保持学习最新的技术。
Web开发唯一不变的是变化。以NodeJS为例:两三年前它并不存在,只有很少(如果有的话)的JavaScript 代码运行于服务器之上。现在,你离不开它。每个Web开发人员都希望留在自己的作品里。要做到这一点,我们必须不停学习最新的技术。如果你是一个后端开 发,这可能代表着学习JavaScript和Node.js,类似于Ruby和Rails。对于前端开发,则可能意味着真正理解CSS3或掌握HTML5 新的API。当然,这并不意味着你必须经常使用它,只需要保持自己不断学习。
按照同样的思路,对于重新评估你的工作流程、学习更好的和不同的工具以更快速地完成工作来说,现在是一个很好的时间。
2 –让你掌握的内容更精深
也要预留一段时间来关注现有的语言和软件。
当然,保持锋利比学习新的内容有更大意义。它也包括改善你使用日常工具的方式。我知道自己一直坚持使用熟悉的的模式和方法而不是学习在某个特定情形下更佳的方案是不对的。你知道关于JavaScript设计模式的那些事吗?你对PHP的面向对象和面向功能编程是否有扎实的理解?你是否曾经使用过SQL连接?你使用的文本编辑器里是否有没有用过的功能?这些都不是新技术,但是如果你不使用它们,它们对你来说就是全新的!也要在关注现有的语言和软件上预留一段时间。
3 -探索一个新的领域
这项内容与第一项并不相同。学习一种新的语言、框架,或自己领域里的方法是重要的,甚至对你的日常实践来说可能会有用。 但如果你像我一样,你会迷上网络上的每一部分。要尝试探索新的领域。对后台开发来说是深入研究前端开发,而对前端来说是探索可用性或用户体验。如果你喜欢 写作,你可能会对内容策略或培养设计灵感感兴趣。在网络上有几十个不同的领域,继续探索!
4 –参与社区
把它叫做参与,把它叫做结网,把它叫做任何你想要的。
该网站极度令人不可思议:我想不出有任何其他的现象,人与人之间相隔那么远,却结下如此深厚的友谊。2012年,你为什 么不更多的尝试参与到这个令人惊讶的团体中呢?在Twitter上与他们交谈,阅读他们博客的文章和评论,或者通过自己写文章来作为回应;通过 Github或其他代码共享网站贡献自己的代码。或者加入自由讨论会,用户组和各种会议。把它叫做参与,把它叫做结网,把它叫做任何你想要的,但有一点是 肯定的:它会在大多数情况下让你和其他人受益。此外,建设新的重要人际关系,你可能会获得新的转机!
5 –教导他人
最有益的评论是伤害你感情的那些。
你应该认同我们之前的观点,在2012年更多的教导他人。为什么呢?它将会带来些什么呢?“教导是最好的学习”?我已经 为Nettuts +写作了近三年,我可以证明,这种说法是完全正确的。写下一个原理是如何工作的能够迫使你完全理解它,当你尝试教导别人时,你会惊讶对这个话题更了解了多 少。最重要的是,当你知道曾经帮助别人学习新的技能时你会有不可思议的感觉。毫无疑问,你将遇到几个反对的声音,例如指出你语法的错误(或只是一些害群之 马的评论)。不用有太多的担心;教学是一个学习的过程,你这样做会提高你自己。最有益的评论是伤害你感情的那些。
6 -更好地照顾自己
我们是网络的受害者。
我们作为Web开发似乎非常自豪,因为我们献出自己的劳动。我们工作时间超长,弓着腰在黑暗中使用计算机,我们忘记了洗澡或吃饭。我们是网络的受害者,忍受着痛苦来让互联网更加美好。
听起来很勇敢,但确实不是这样。
为你的风险考虑,我建议你在2012年照顾好自己。除了睡得好,吃得好,确保你的工作场所符合人体工学。按理说,如果你花了生命中的三分之一在办公室,使其尽可能舒适是很有道理的!
7 –更好的管理自己的时间(以及其他资源)
也许我并不是指这和Web开发人员有很大关系,但尽管如此,几乎每一个“知识工作者”可以做得更好。对于我们里的很多人,尤其是自由职业者来说,你要用你的时间来做的事可能是灯红酒绿和饥肠辘辘之间的差异。记住所有的这些乐趣,以及我向你推荐学习的Web新技术了吗?好了,不要让它们的引诱限制你的学习时间。当然互联网越大越会有更多诱惑。我敢肯定,你最近看到了下面的内容,当我这么做时它给了一个暂停。
在过去的一年里,超过1万亿美元的视频在Youtube上被观看。
假设平均YouTube视频是2 – 3分钟之久,我们正在寻找的东西可以花上一整天的时间。在知识方面我还没有足够精深。
当然,“只是工作,不要娱乐”,完全按此行事是正确的吗?我不建议你成为客户的一个奴隶或者是不能忍受沉闷的工作狂。我只是说,我们需要更明智的来明确了解我们每小时是如何度过的,并努力的更好利用时间。
8 –采用更好的编程实践
过度的文档永远不会是坏事。
不,我不是在用两个不同的词汇重复同一个决定。这一次,我谈论的做法围绕编码本身的实践。我不能告诉你我有多少次热切地 开始了新的项目,然后一个半小时后说,“嗯。。。我要为尝试这个功能创建一个分支。噢,等一下,我忘了开始时初始化Git。。“确保我记得从一开始就使用 代码版本是我在2012年还要去面对的工作,它能使你的项目历史更清晰。
另一个我经常忽略的基本编码实践是注释。我可以变出许多行巧妙的代码,然后在剩下的时间里为其他事情分心。第二周我回到 工作里时花了20分钟试图弄清楚它。这会困扰你吗?请你给自己帮个忙,为自己和其他人留下有用的注释。文档和注释是同样正确的事情。我最近在学习 Dojo,我发现它的代码文档是无价的。当然,文件的水平将取决于你的项目的公开程度,但是我认为过度的文档永远不会是坏事。
9 -产生被动收入
我猜Nettuts +的绝大多数读者做客户端的工作,无论是作为一个自由职业者或以其他方式。那么为什么不另外获取一些被动收入呢?Envato(译者注:自由职业者创建的著名公司,旗下有销售类、教程类和博客类的网站)有十个市场,在这里任何具有合适技能的人都可以获利。为ThemeForest(译者注:国外知名设计网站)构建一个主题,为CodeCanyon写一个脚本,其潜在价值永无止境。当然,如果你的技能不适合Envato市场,或者即便可以,还有其他许多方法可以产生被动收入。例如如果你是一个作家,可以试试Tuts+ Premium(译者注:一个学习设计、Web开发技术的网站)。他们一直在寻找充满激情的新教师。
在市场或个人网站上销售项目是一个聪明的方式,可以被动地获取一些额外的现金,同时你还能做自己享受的事情。
10 –给自己放个假
戴上一顶完全不同的帽子…在有些时候
到目前为止,前面的每一个决定是你可以做的一些事情来改善你作为开发者的技能。我会密切指出,你要成为一个优秀开发者可 以做的最好的事情之一就是不要成为一个开发者。。。在有些时候。有时候需要戴上一顶完全不同的帽子。保持甚至和开发毫不相关的一项爱好,而且最好不要涉及 电脑。玩某种乐器,阅读,写作,开拓厨艺。不管你做什么,留下一些放松的时间。当你这样做时会发现,编程问题的解决方案往往出现在休息时间。
我曾经用在开车回家路上的思考解决了许多代码问题。
当然,定时休息是很重要的,还有那些一年几次更长时间的休假。此外扔了那些年度计划!
你的决定?
好了,这就是Web开发者应做的十项决定的清单。你觉得有哪些不在我的名单上?让我们在评论中来听听这些意见!
蒋宇捷译自:http://net.tutsplus.com/articles/general/ten-new-years-resolutions-every-web-developer-should-make/
安德鲁 伯吉斯于2011年12月27日
原文链接:http://blog.jobbole.com/11810/
1956年的5MB“大”硬盘 来自IBM
0还在抱怨 3.5 吋的硬盘盒不方便携带或是云端空间一点都不够用吗?这台IBM 的 305 RAMAC(Random Access Method of Accounting and Control)想必可以完全改变你的想法。
照片中这「块」嗯… 应该说是这台 1956 年的 IBM 硬盘,内部主要是由 50 片 24 吋的磁盘所构成。这个 16 平方英尺的庞然大碟,除了每年固定耗费 US$35,000 外,而且还仅具有 5MB 的储存空间,姑且不论当时的高科技的在现在看来有多么渺小(一首 MP3 顶多吧?),但 RAMAC 其超过一吨的重量却肯定让你无法忽略它的存在。现在,让我们开始感谢科技的进步吧!
全球范围60秒钟内发生的与科技相关的有趣事情
0在60秒钟内,苹果可以卖出925 部iPhone 4s和85台iPad。是不是觉得这不可能?上图是Go-Gulf网站给我们做出的一张信息图表,它向我们体现了在60秒钟内会发生的19件有趣的事情。60秒钟在全球范围内发生的事情:
-全球售出710台电脑,其中有555台用的是Intel的处理器
-生成1820TB的数据,足以录入2600万张CD之中
-232台电脑受恶意软件感染
-450张Windows 7 Cd售出
-925 部iPhone 4s和85台iPad售出
-11台Xbox 360售出
-18台Kindle Fire售出
-产生38吨电子垃圾
-4000部USB设备售出
-2500个墨盒售出
-Foursquare网站有2100次用户注册
-谷歌收入增加75,000美元
-200万网络用户在线收看色情内容
-即时通许工具上发生110万次对话
-103部黑莓手机售出
-玩家在Farmville农场游戏中耕种1100英亩的“土地”
-PayPal处理交易额高达219,000美元,其中有10,000是通过PayPal mobile完成
-eBay上完成950次购买,其中有180次购买是通过eBay Mobile完成
-黑客攻击12个网站,而Facbook账户遭受416次尝试攻击
-在线电影租借服务Redox租出1400张电影光盘
当string LoveYou(char* Me){}返回的不是”LoveYou2″
0有的女人就像UNIX,她条件很好,然而不是谁都能玩的起.
有的女人就像C#长的很漂亮,但是家务活不行.
有的女人就像C++,她会默默的为你做很多的事情.
有的女人就像JAVA,只需一点付出她就会为你到处服务.
有的女人就像JAVA Script,虽然对她处处小心但最终还是没有结果.
有的女人就像汇编 虽然很麻烦,但是有的时候还得求它.
有的女人就像 SQL,她会为你的发展带来莫大的帮助.
爱情就是死循环,一旦执行就陷进去了.
爱上一个人,就是内存泄露,你永远无法将他释放.
真正爱上一个人的时候,就像是常量限定,永远不会改变.
女朋友就是私有变量,只有我这个类才能调用.
情人就是指针用的时候一定要注意,要不然就带来巨大的灾难
但是我不能抽象出你….
因为你在我心中是那么的具体….
所以我的世界并不完整….
我可以重载甚至覆盖这个世界里的任何一种方法….
但是我却不能重载对你的思念….
也许命中注定了 你在我的世界里永远的烙上了静态的属性….
而我不慎调用了爱你这个方法….
当我义无返顾的把自己作为参数传进这个方法时….
我才发现爱上你是一个死循环….
它不停的返回对你的思念压入我心里的堆栈….
在这无尽的黑夜中….
我的内存里已经再也装不下别人….
我不停的向系统申请空间….
但却捕获一个异常——你爱的人不爱你….
为了解决这个异常….
我愿意虚拟出最后一点内存….
把所有我能实现的方法地址压入堆栈….
并且在栈尾压入最后一个方法——将字符串"我爱你,你爱我吗?"传递给你….
如果返回值为真--我将用尽一生去爱你….
否则——我将释放掉我所有的资源….














