CRectTracker(橡皮筋)

 建立一个单文档的工程文件,将其命名为Rect。单击finish完成工程的建立;先编译一下,来第一次生成obj文件吧,在它生成的过程中,我们继续往下讲解;

第一步:
在CRectDoc类中生成一个公有的数据成员:m_rectTracker;之所以设成公有,因为要在View中调用它。接着我们来初始化它,在CRectDoc::CrectDoc构造函数中:


  CRectDoc::CRectDoc()
 { // TODO: add one-time construction code here
        m_rectTracker.m_rect.SetRect(0,0,100,100);
        m_rectTracker.m_nStyle=CRectTracker::resizeInside|CRectTracker::dottedLine;
  }

其中: m_rect是CRectTracker中用来控制四边形的大小位置的数据成员, SetRect使用的是View的坐标; m_nStyle是CRectTracker的类型,其中:CRectTracker::resizeInside和CRectTracker::resizeOutside是说明在m_rect的内部还是外部画区域(它们是互异的),CrectTrakcer::dottedLine是用点划线来画四边形的区域边界。 其他的值还有: CRectTracker::solidLine:用来画实线边界;(和dottedLine是互异的) CRectTracker::hatchedBorder:边界带抛面线; CRectTracker::hatchInside:内部带抛面线; 你可以运行前面的例子,上述参数都有使用。你也可以在第二步中逐一使用它们来加深理解它们各自的含义;

第二步:
接着我门在视图中画一个蓝色的椭圆; 在CRectView的OnDraw中继续我们的工作:

void CRectView::OnDraw(CDC* pDC)
{
     CRectDoc* pDoc = GetDocument();
     ASSERT_VALID(pDoc);
     // TODO: add draw code for native data here
     CBrush brush(RGB(0,0,255));//生成蓝色的画刷;
     CBrush  *oldBrush=pDC->SelectObject(&brush);//将画刷选进dc;
     CRect rect;
     //GetTrueRect(&rect)得到CRectTracker中的m_rect的大小,将其传递给rect;
     pDoc->m_rectTracker.GetTrueRect(&rect);
     pDC->Ellipse (rect);//画椭圆;
     //Draw tracking rectangle.
     pDoc->m_rectTracker.Draw(pDC);//这句画才真正的将这个四边形画出来;
     //Select blue brush out of device context.
     pDC->SelectObject (oldBrush);//恢复原来的画刷;
}

注释已经在程序里了,不用再多说,编译一下。一个椭圆外带四边形边界(点划线),且四边形的四周有八个黑点;这就是CRectTracker.,你现在可以改变一下m_nStyle试试看各参数的含义;

第三步:如何象例子中的那样随着鼠标的移动自动在椭圆的周围改变光标呢?很简单只要将下面的代码加入到CRectView::OnSetCursor()就可以了:它调用了CRectTracker中的SetCursor()函数:

BOOL CRectView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{ // TODO: Add your message handler code here and/or call default
     CRectDoc* pDoc  = GetDocument();
     if (pWnd == this && pDoc->m_rectTracker.SetCursor(this, nHitTest))
          return TRUE;
     return CView::OnSetCursor(pWnd, nHitTest, message);
}
编译运行一下,鼠标变化了。 第四步:我们再做另一个用于鼠标的CRectTracker类。它的作用是在鼠标按下以后可以显示虚线的选择框: 先让我们看看效果:
在CRectView中的加入如下代码:

void CRectView::OnLButtonDown(UINT nFlags, CPoint point)
{
    CRectTracker temp;
    temp.TrackRubberBand(this,point,TRUE);
    temp.m_rect.NormalizeRect();//正规化;
    CView::OnLButtonDown(nFlags, point);
}


编译运行,当你按下鼠标并拖动,你将看到效果了。
我们如何让鼠标画一个“橡皮筋”区域呢? 在CRectTracker类中的成员函数就是:TrackRubberBand(this,point,TRUE); 注意其中的三个参数:
第一个参数,画“橡皮筋”的窗体的指针,当然是this
第二个参数,画“橡皮筋”的起始点。
让我们注意第三个参数,它非常有意思。当你使用 FALSE时(TRUE 值是缺省的),你的“橡皮筋”只能从左上到右下的画,不允许反向。编译运行一下FALSE这个值。
特别值得注意的是:在TrackRubberBand的过程中是以右键的抬起为结束的,这其间并没有CView的MouseMove发生。这一点一定要记住!这时鼠标画过的区域已经记录在temp的m_rect 中了,你可以根据它进行后续的判断工作。至于下面的正规化语句函数的作用与CRect中的正规化函数的作用一致:使四边形的四个角的坐标符合右大于左,底大于顶的坐标值。它主要是为了防止你使用TrackRubberBand 的FALSE参数而引起的可能出现的错误。

第五步:
让我们回到那个蓝色的椭圆,在开始新的步骤之前,首先来介绍一下HitTest(CPoint point)的功能:当你鼠标被按下的时候,你可以调用这个函数,它将返回鼠标点在了四边形的什么位置:

返回值
 代表的含义
 
-1
 点在了四边形的外部
 
0
 左上角
 
1
 右上角
 
2
 右下角
 
3
 左下角(0,1,2,3顺时针转了一圈)
 
4
 顶部
 
5
 右部
 
6
 底部
 
7
 左部(还是顺时针转了一圈)
 
8
 点在了四边形的内部,但没有击中前面的那八个点
 

可以看出,返回值如果大于等于零则在四边形区域之内。如果小于则说明不在区域范围之内。因此我们需要加一个公有的成员函数:BOOL bDraw;为了方便起见,我把它加到CRectView中,(你也许会说,为什么不加到doc中,我也知道这有勃编程的原理,反正我高兴就得,都说C++给人了很大的自由度,所以你也别限制我)。先把它初始化为FALSE,表示不画边界,当TRUE时,表示要画边界。 定义:
class CRectView : public CView
{
   …………
   public:
   BOOL bDraw;
   …….
}
初始化:
CRectView::CRectView()
{
      // TODO: add construction  code here
      bDraw=FALSE;
}
将OnDraw改一下,加一句话:
void CRectView::OnDraw(CDC* pDC)
{
      CRectDoc* pDoc = GetDocument();
      ASSERT_VALID(pDoc);
      // TODO: add draw code for  native data here
      CBrush brush(RGB(0,0,255));//生成蓝色的画刷;
      CBrush  *oldBrush=pDC->SelectObject(&brush);//将画刷选进dc;
      CRect  rect;
      pDoc->m_rectTracker.GetTrueRect (&rect);
      //GetTrueRect(&rect)可以得到CRectTracker中的m_rect的大小,将其传递给rect;
      if(bDraw) //*************新加的语句***************
         pDC->Ellipse (rect);//画椭圆;
       //Draw tracking rectangle.
      pDoc->m_rectTracker.Draw (pDC);//***这句画才真正的将这个四边形画出来;***
      //Select blue brush out  of device context.
      pDC->SelectObject (oldBrush);//恢复原来的画刷;
}
      编译运行一下,椭圆的边界没有了。
      好了,预备知识讲完了,让我们来完成这个程序吧:
void CRectView::OnLButtonDown(UINT nFlags, CPoint point)
{
      // TODO: Add your message  handler code here and/or call default
      int nIn; //定义一个鼠标的点击值;
      nIn=GetDocument()->m_rectTracker.HitTest(point); //看看点到了哪了
      if(nIn<0)  //不在四边形区域内;
      {
      CRectTracker  temp;
      temp.TrackRubberBand(this,point,TRUE);
      temp.m_rect.NormalizeRect();
      CRectTracker interRect;
      //在建立一个CRectTracker;用于记录鼠标与椭圆的交集。
      if(interRect.m_rect.IntersectRect(temp.m_rect,GetDocument()->m_rectTracker.m_rect))
       bDraw=TRUE; //如果有交集,则画四边形的边界,说明选择了椭圆
      else   bDraw=FALSE;
      Invalidate(); //引起OnDraw函数的发生;
      }
      else
        //在四边形区域内:
      {
      CClientDC dc(this);
      GetDocument()->m_rectTracker.Draw(&dc);
      GetDocument()->m_rectTracker.Track(this,point,TRUE);
      // Track()是CRectTracker中最富魅力的函数。它时时的改变调用者的m_rect;
      bDraw=TRUE;
      Invalidate();
      }
      CView::OnLButtonDown(nFlags, point);
}
你也许会问,为什么我没有编写MouseMove函数,它就自动的变大小了呢?这就是Track()函数的功劳,从调用它到抬起鼠标键为止,它时刻的改变m_rectTracker的四边形的大小。然后由于我们使用了Invalidate()函数,所以重新画了这个椭圆,因此它好象被放大缩小了似的。 我的文章写完了,还有什么不懂的地方,写信给我。在关闭这个文件之前,最好你自己再复习一下,并尝试一下其他的功能。

<think>好的,我现在需要帮助用户了解或实现得物签名的相关技术,特别是签名算法的实现方式。首先,我需要收集已有的信息。根据用户提供的引用,特别是引用[4]和[5],得物的签名算法可能涉及逆向工程分析,使用了JavaScript中的XMLHttpRequest重写来拦截请求,并在请求中包含特定的sign参数。这可能意味着签名生成是在客户端进行的,通常在前端JavaScript代码中完成。 接下来,我应该考虑常见的签名生成方法。常见的Web应用签名算法通常使用HMAC、AES、RSA或自定义的哈希组合。引用[1]提到了RSA算法,但得物的签名可能更倾向于使用HMAC-SHA256之类的哈希算法,结合时间戳、随机数和请求参数进行签名,以防止篡改和重放攻击。 用户可能需要具体的步骤,比如逆向分析得物的JavaScript代码,找到生成sign的函数,提取关键参数和加密逻辑。引用[5]中的代码片段展示了如何重写XMLHttpRequest的open方法来拦截请求,这可能用于调试和定位签名生成的代码位置。 此外,引用[4]提到使用Python进行算法还原,所以可能需要在Python中复现JavaScript的签名生成逻辑。这通常涉及分析请求参数如何排序、拼接,以及如何与密钥结合进行哈希或加密。需要注意反爬机制,如obfuscation(代码混淆)或动态密钥,这可能需要使用AST(抽象语法树)解析或动态执行来还原算法。 用户可能还需要了解如何应对反调试措施,比如在Chrome开发者工具中使用断点调试,或者使用工具如Frida进行Hook。同时,引用[3]和[4]强调了法律和合规问题,确保研究仅用于学习目的,不用于非法用途。 最后,应该提醒用户注意法律风险,遵循网站的使用条款,避免侵犯知识产权或违反计算机安全法律。总结起来,实现得物签名需要逆向工程分析前端代码,提取关键算法,处理可能的混淆和反调试,最后用目标语言如Python复现算法。</think>### 得物签名算法实现方式分析 得物签名算法主要用于接口请求的身份验证和防篡改保护,常见实现方式涉及以下技术点: #### 1. **签名参数组成** 签名通常由以下参数动态生成: - 请求参数(经排序、过滤空值后拼接) - 时间戳(如:$timestamp=1620000000$) - 随机数(如:$nonce=5a8s3d$) - 设备指纹(如:$device\_id=abcdef$) - 应用密钥(加密盐值,可能动态获取)[^4] 示例参数拼接逻辑: $$ \text{sign\_str} = \text{path} + \text{sorted\_params} + \text{timestamp} + \text{nonce} $$ #### 2. **加密算法类型** 根据逆向分析,得物可能采用以下组合: - **HMAC-SHA256**:对拼接字符串进行哈希运算 - **AES/Base64编码**:对结果二次处理 - **自定义位移/异或操作**:增加逆向难度[^5] #### 3. **JavaScript代码混淆** 关键函数可能被混淆,例如: ```javascript function _0x12ab5(a, b) { return a ^ b << 3; } // 需要AST解析还原控制流 ``` #### 4. **Python算法还原示例** ```python import hmac import hashlib def generate_sign(params, secret_key): # 1. 参数排序并拼接 sorted_str = '&'.join([f"{k}={v}" for k,v in sorted(params.items())]) # 2. HMAC-SHA256加密 sign = hmac.new(secret_key.encode(), sorted_str.encode(), hashlib.sha256).hexdigest() # 3. 自定义处理(示例) return sign.upper() + str(int(time.time())) ``` #### 5. **反爬对抗措施** - 动态密钥:通过接口定期更新加密盐值 - 环境检测:验证是否在真机环境运行 - 请求频率限制:异常高频触发验证码[^5]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值