# \_msgsender()绕过

存在漏洞的代码

```solidity
    function _msgSender() internal override virtual view returns (address payable ret) {
        if (msg.data.length >= 24 && isTrustedForwarder(msg.sender)) {
            // At this point we know that the sender is a trusted forwarder,
            // so we trust that the last bytes of msg.data are the verified sender address.
            // extract sender address from the end of msg.data
            assembly {
                ret := shr(96,calldataload(sub(calldatasize(),20)))
            }
        } else {
            return msg.sender;
        }
    }
```

我们看到`_msgSender()`的实现上，并不总是返回msg.sender。**在某一条件下，会返回一个奇怪的汇编代码** (通过注释也能看出，**这段代码返回的是calldata中最后一个地址变量**) `ret := shr(96,calldataload(sub(calldatasize(),20)))`

> **Note**: calldatasize 返回的是 msg.data 的字节长度，比如 call(addr1, addr2) 的 calldatasize = 4 + 20 + 20 = 44 bytes

calldataload(i) 返回从i开始的一个 uint256，即 msg.data\[i:i+32] (这里的32是bytes=256bit), 所以 calldataload(sub(calldatasize(),20)) 返回的是 msg.data 的后 20bytes (一个address的长度)

以call(0x70873211cb64c1d4ec027ea63a399a7d07c4085b, 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)为例: 返回的就是: res = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc200000000000…

接着 shr(96, res)，将 res 右移96位(12bytes)，变成 0x00000….C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

> **Note**: 关于Forwarder以及本合约中的\_MsgSender实现，是为了兼容GSN(<https://opengsn.org/>) Token
>
> GSN Token可以帮助用户，在没有原生代币 (native token) 的情况下发送交易。我们知道发送交易是需要Gas费的，一般Gas费都是用某个链的原生代币来支付 (比如: ETH)
>
> 那为什么存在没有原生代币，还需要发交易的情况呢？这个如果有过经历的很容易理解。比如我刚入行区块链的时候，参加过一次Web3活动，刚好某个项目现场发放aridrop。于是，我第一次下载钱包 (入坑开始..)，生成地址，项目方把他们的代币转到我这个新开的地址
>
> 但是，由于新的账户，里面一个ETH都没有，这些代币完全没法交易或提走。这时，GSN作为一个第三方的服务，可以代替我支付Gas费，相应的，我用我空投得到代币支付给他。
>
> 简单来说，我对我要做的事情进行签名，通过网络发送给GSN，GSN生成一笔交易，这笔交易内部完成了我的交易。问题来了，由于GSN代我发送的交易，msg.sender是GSN，如何将内部我的地址暴露出来作为这笔交易的"msg.sender"呢
>
> 这时，支持GSN的合约，就会使用\_msgSender这样的方法，对数据进行一次剥离，暴露出真实的msg.sender

参考<http://101.37.161.120/defi/docs/rekt/2022-01-18-crosswise/>
